Добавление к ответу @MM, похоже, даже если у вас есть функции-члены publi c constructor
и setter
для класса A
, компилятор по-прежнему сохраняет члены-данные класса B
в области заполнения класса A
(я пытался заставить компилятор не использовать хвостовое заполнение класса A
, но это не удалось).
Примечание можно найти в class.mem / 19 , говорящем:
[Примечание: Non-stati c членов данных (не Класс union) с тем же контролем доступа и ненулевым размером ([intro.object]) размещается так, чтобы более поздние члены имели более высокие адреса в объекте класса. Порядок распределения элементов данных без учета c с различным контролем доступа не определен. Требования выравнивания реализации могут привести к тому, что два смежных элемента не будут выделяться сразу после друг друга; то же самое касается требований к пространству для управления виртуальными функциями ([class.virtual]) и виртуальными базовыми классами ([class.mi]). - конец примечания]
Добавление дополнительных от этого ответа:
Стандарт требует, чтобы элементы с одинаковым контролем доступа были сгруппированы в памяти. Эта группировка решает, как объект будет дополнен, поэтому изменение может изменить размер объекта.
И еще от этот ответ:
Dsize, nvsize и nvalign этих типов определены как их обычный размер и выравнивание. Эти свойства имеют значение только для непустых типов классов, которые используются в качестве базовых классов. Мы игнорируем хвостовое заполнение для POD, потому что ранняя версия стандарта не позволяла нам использовать его для чего-либо еще, и потому что иногда это позволяет быстрее копировать тип.
Таким образом, в вашем первом примере A
не является POD для целей компоновки, и его хвостовое заполнение может использоваться для B::val
, но во втором примере это POD
, и его хвостовое заполнение не может использоваться повторно.
#include <iostream>
class A {
int val;
char c;
public:
A(int a, char b): val(a), c(b)
{
}
public:
void setC(int a)
{
c = a;
}
char getC(void) const
{
return c;
}
};
class B: public A {
char val;
public:
B(void): A(1,'2'), val('2')
{
}
public:
char getVal(void) const
{
return val;
}
};
struct C {
int val;
char c;
};
struct D: public C {
char val;
};
int main()
{
B a;
a.setC(2370);
std::cout << a.getVal() << " & " << a.getC() << std::endl;
std::cout << sizeof(B) << std::endl; // 8
std::cout << sizeof(D) << std::endl; // 12
return 0;
}
Выходы:
2 & B
8
12
Чтобы узнать о memory order and alignment
для классов, см. this .