2016-12-30 4 views
2

Я заметил странное поведение в множественном наследовании. Давайте посмотрим на следующем примере:C++: Неожиданный размер объекта класса в множественном наследовании

#include <iostream> 
using namespace std; 

struct A {}; 
struct B : public A { double x; }; 
struct C : public A, public B {}; 

int main() { 
    cout << "Size of double: " << sizeof(double) << endl; 
    cout << sizeof(A) << ", " << sizeof(B) << ", " << sizeof(C) << endl; // gives 1, 8, 16 
} 

размер типа равен 1 (странно, но приемлемо), размер типа B равно 8 (такой же, как двойного типа, который, как ожидается), но размер C type ... равно 16. Что еще более странно, когда я пытался найти неожиданную переменную, я не мог ее идентифицировать.

struct D { double a, b; }; 

C c; 
auto &d = reinterpret_cast<D&> (c); 
d.a = 1; 
d.b = 2; 

cout << c.x << endl; //gives 2 
cout << c.B::x << endl; //gives 2 
cout << c.C::x << endl; //gives... 2 

cout << d.a << ", " << d.b << endl; //gives 1, 2 

Я получил этот путь совершенно неожиданное поле данных в объекте, и я не могу получить доступ к нему обычным способом. Есть ли способ объяснить это? Ожидается ли поведение от компилятора C++?

Кстати, код был написан и составлен в Visual Studio 2015, 64x, но когда я составил первую часть на г ++ (Ubuntu), результат был тот же - 1, 8, 16.

Ах, указать моя проблема - я хотел бы хранить большое количество данных, указанных как унаследованный тип, поэтому меня беспокоят бесполезные зарезервированные байты. Если у кого есть решение, я буду рад услышать - даже если это #define или вариант компиляции.

+0

'align_up (1, 8) + 8 = 16' –

ответ

2

Да, C++ разрешает размер пустого базового подобъекта быть 0 байтами, это вызов empty base optimization. Но каждый объект должен иметь уникальный адрес, поэтому sizeof пустая реализация экземпляра на свой собственный - 1 байт.

+0

Я могу согласиться с тем, что размер пустого типа может быть равен 1 байту, но как насчет этой проблемы с 16 байтами? – Ch3shire

+0

Это объясняет, что 'sizeof A' равен 1, но он не объясняет, что' sizeof C' равен 16 - «пустая оптимизация базы» означала бы ее 8. – user4815162342

+0

Хорошо, ваша ссылка объясняет это достаточно. Спасибо :) – Ch3shire

4

Существует не очень много удивления здесь:

  1. Вы получили два A подобъектов в C: первый сразу наследуется C и второй один косвенно унаследована через B. Эти два подобъекта должны иметь разные адреса.
  2. double в B хочет быть выровненным с подходящим адресом, т. Е. При необходимости будет заполнение, чтобы убедиться, что оно находится на границе 8 байтов (как правило, нет мандата на заполнение или размер любого такого дополнения).
  3. Чтобы создать массив объектов (который определяет размер, о котором сообщает sizeof()), объект будет дополняться независимо от того, на каком размере находится ближайший 0OBподобъект.

Обратите внимание, что проблема существует полностью, потому что у вас есть две пустые базы одного типа! Если у вас есть другая база, которая также пуста, она может законно поделиться адресом A, и весь размер объекта будет только 8.

+0

Nope. Когда я использовал 'struct C: public D, public B {};' с D как пустой класс, проблема была такой же. – Ch3shire

+0

@ Ch3shire: это, безусловно, 8 при использовании C++ ABI, полученных из Itanium ABI. –

+0

Предположим на секунду, что я не компьютерный ученый и просто хочу оптимизировать размер объекта. Я проверил термин ABI на wiki ...ну, мне слишком сложно использовать хардкор :) – Ch3shire

Смежные вопросы