Интересно выяснить, какие размеры имеет класс-потомок при обычном и виртуальном множественном наследовании. Начнем с пустых классов и будем добавлять туда поля и придавать им виртуальность:
class А{ };
class Bl: public А { };
class В2: public А { };
class D: public Bl, public B2 { };
cout << sizeof(A) << endl:
cout << sizeof(Bl) << endl;
cout << sizeof(B2) << endl;
cout << sizeof(D) << endl;
На экран, естественно, выводится четыре единицы — размеры пустых классов. Добавим поле short в класс А:
class А { short а; };
class Bl: public А { };
class В2: public А { };
class D: public Bl, public B2 { };
Получим цифры 2, 2, 2, 4 — это как раз говорит о том, что поле базового класса А класс-наследник D унаследовал дважды: от В1 и от В2. Добавим в класс А поле типа char, чтобы его длина была равна трем, а наследование сделаем виртуальным:
class А { short a; char b; }; class Bl: virtual public A { };
Я думаю, мы достаточно много сравнивали Visual C++.NET 2003 и С++Builder 6, поэтому ограничусь только первой системой в режиме #pragma pack(l).
class В2: virtual public А { }; class D: public Bl, public B2 { };
Тогда получим размеры 3, 7, 7, 11. Очевидно, виртуальное наследование добавило в классы В1 и В 2 по 4 байта. Можно предположить, что это — размер указателя (мы работаем на платформе intel под Windows). Тогда класс D получил 3 байта от базового класса и 2 указателя (от В1 и от В2).
Теперь один класс унаследуем виртуально, а другой — обычно:
class А { short a; char b; }; class Bl: public A { }; class B2: virtual public A { }; class D: public Bl, public B2 { };
В результате получаем 3, 3, 7, 10. Это означает следующее: класс А имеет размер 3 байта; класс В1 (простой наследник) унаследовал эти 3 байта; виртуальный наследник В 2 имеет размер 3 + 4 = 7 байт, а последний производный класс получил размер 3 (от А) + 3 (от В1) + 4 (указатель от В2) = 10 байт.
При виртуальном наследовании добавим в класс А виртуальный деструктор:
class А { short a: char b: virtual ~А() {} }; class Bl: virtual public A { }; class B2: virtual public A { }; class D: public Bl, public B2 { };
Размеры классов, естественно, увеличиваются на 4 байта — размер указателя на таблицу виртуальных функций: 7, 11, И, 15.
Таким образом, мы наблюдаем, что на этапе выполнения программы виртуальное наследование увеличивает накладные расходы. |