2016-02-19 1 views
2

Я читаю - 3.4 Наследование и член данных. В нем говорится «языковая гарантия целостности подобъекта базового класса в производном классе». Кроме того, это дает пример следующим образом:Объектная модель C++ по gcc 4.4.7: дополнение субобъектов базового класса, занятое в объекте производного класса

class Concrete1 
{ 
private: 
    int val; 
    char bit1; 
}; 

class Concrete2 : public Concrete1 
{ 
private: 
    char bit2; 
}; 

class Concrete3 : public Concrete2 
{ 
private: 
    char bit3; 
}; 

объектная модель Concrete1 является:

4 bytes for val, 
1 byte for bit1, 
3 bytes padding. 
// 8 bytes in total. 

объектная модель Concrete2 является:

8 bytes for Concrete1 subobject, 
1 byte for bit2, 
3 bytes padding. 
// 12 bytes in total. 

Аналогичным образом, модель объекта Concrete3 составляет 16 байтов ,

Объект-участник Concrete2 bit2 не использует дополняющую часть субобъекта Concrete1, поэтому он составляет 12 байтов. Но когда я попробовал пример в gcc 4.4.7, объект Concrete2 и объект Concrete3 имеют тот же размер, что и объект Concrete1 - 8 байт. Поэтому я предполагаю, что gcc использует дополняющую часть объекта Concrete1 для хранения бит2 и бит3. Я называю их «не-использование-padding» и «use-padding» для краткости.

Для того, чтобы объяснить, почему обивка часть не используется, книга дает следующий код:

Concrete2 *pc2; 
Concrete1 *pc1_1, *pc2_2; 
pc1_1 = pc2; 
*pc1_1 = *pc2_2; // pc1_1 may point to a Concrete2 or Concrete3 object. 

В «не потребительной отступа» способом, объект Concrete1 указывает pc2_2 будут скопированы к подобъекту Concrete1 объекта Concrete2/Concrete3, на который указывает pc1_1. В книге также говорится, что это «членная» копия, но она больше похожа на копию «объекта», так как она также копирует часть дополнений.

В книге «use-padding» в книге говорится, что он переопределит элемент bit2, потому что соответствующий байт * pc2_2 является байтом заполнения. Опять же, я попробовал это с gcc 4.4.7, оказалось, что элемент bit2 не переопределен. Поэтому я предполагаю, что копия является реальной копией «по порядку», скопированы только val и бит1.

Итак, мои вопросы: 1. Я правильно отношусь к действиям gcc: «use-padding» и реальная копия «по порядку»? 2. Частные члены базового класса не могут быть доступны в производном классе, но объект производного класса содержит все частные члены в подобъекте базового класса (val и бит1) в объектной модели. Почему он предназначен для размещения закрытых членов базового класса, даже если их невозможно получить в объекте производного класса? Просто для операций копирования, таких как * pc1_1 = * pc2_2; ?

Благодаря

+0

# 2: Обычно класс будет иметь функции открытого члена, которые, в свою очередь, используют частные данные. Даже если производный класс не может получить доступ к своим частным членам своего базового класса, он может, безусловно, вызвать его общедоступные методы. –

+0

Вы хотите прочитать C++ Itanium ABI, который описывает (часть) макет, используемый gcc. В частности, это показывает, что если вы замените 'private:' на 'public:' в Concrete1, размер производных классов изменится. –

ответ

0

О ваш первый вопрос:

Я пытался воспроизвести поведение, описанное в «Use-отступы» в ideone.com с различными компиляторами, но не удалось. Clang, gcc 4.3 и gcc 5.1, казалось, не использовали заполнение базового класса. Но из ответов на вопрос this Question можно прочитать, что gcc действительно использует это дополнение.

Стандарт вводит понятие POD-types, но явно сказано

9 Классы [класс]
(...)
7 класс S класс стандартного макета если он : (...)
(7.6) имеет все нестатическую элементы данных и битовые поля в классе и ее базовые классы первым объявлены в одном классе (...)

Так что это не относится к классу, так как у вас есть данных как в базовом, так и в производном классах. Я не мог найти никаких ссылок о том, как не-POD-типы должны быть оформлены. В одном из ответов в связанном вопросе говорится, что это стало предметом изменений.

Что важно в отношении наследования, так это использование указателей или ссылок - вы можете использовать производный объект, как если бы он был объектом базового класса. Это означает, что вы можете использовать Concrete3*, как если бы это был Concrete1*. Но это зависит от того, используете ли вы прокладку или нет, если вы не меняете компоновку Concrete1 при добавлении данных из Concrete2 и Concrete3.


О втором вопросе:

Стандартные состояния это:

11 контроля доступа Член [class.access]
1 Член класса может быть

  • (1.1) частный; то есть его имя может использоваться только членами и друзьями класса, в котором он объявлен.
  • (1.2) защищенный; то есть его имя может использоваться только членами и друзьями класса, в котором он объявлен, классами, полученными из этого класса, и их друзьями (см. 11.4).
  • (1.3) public; то есть его имя может использоваться везде без ограничения доступа.

Как вы можете видеть, в нем указывается, где можно использовать имя. Например. вы все равно можете вернуть ссылки или указатели на частных пользователей. Это означает, что они должны присутствовать в памяти где-то. Фактически состояние объекта определяется состоянием его членов - частным или общественным - это просто вопрос, где в вашем коде вам разрешен прямой доступ к ним.