Почему компиляторы (например, gcc) работают с макетом памяти производных классов таким образом?

Вот мой код cpp.

#include <iostream>
using namespace std;

class A {
public:
int val;
char a;
};

class B: public A {
public:
char b;
};

class C: public B {
public:
char c;
};

int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;

return 0;
}

Вывод программы (в gcc):

8
12
12

Этот вывод меня сильно смущает.

Я знаю, что выравнивание может быть причиной, по которой sizeof (A) равен 8. (sizeof(int) + sizeof(char) + 3 bytes padding)

И я также думаю, что расширение sizeof (B) (sizeof(B) == sizeof(A) + sizeof(char) + 3 bytes padding), чтобы избежать дублирования при копировании. (это правильно?)

Но что я действительно не знаю, почему sizeof (B) равен sizeof (C).

Большое спасибо.

8

Решение

И GCC, и Clang следуют Itanium C ++ ABI документ, в котором указаны:

… Реализации могут свободно размещать объекты в дополнении хвоста любого класса, который не был бы POD в C ++ 98

class A это POD, поэтому компилятор не может поместить материал в его дополнение. class B это не POD, поэтому компилятор может повторно использовать заполнение в макете базового класса для членов производных объектов. Основная идея здесь заключалась в том, что макет класса C ++ должен отражать эквивалентный макет структуры C для типов POD, но для других классов нет ограничений. Поскольку значение «POD» менялось несколько раз, они явно используют определение из C ++ 98.

РЕДАКТИРОВАТЬ: Об обосновании. POD-типы — это очень простые классы, которые могут быть реализованы как struct в C. Для этих типов компоновка должна быть идентична компоновке, создаваемой компилятором C. В частности, они хотят, чтобы C-инструменты, такие как memcpy за A, Если char b; были в пределах дополнения A, memcpy уничтожит это.

13

Другие решения


По вопросам рекламы [email protected]