В книге «Inside the C++ Object Model» указано, что производный класс имеет n - 1
дополнительных виртуальных таблиц, что n
- это число базовых классов. Я провел несколько экспериментов с компилятором g ++, а мой компьютер - 64 бит. Ниже приведен мой код.Как компилятор g ++ реализует множественное наследование с виртуальными функциями?
class A{
private:
int a;
public:
virtual void print() const{
cout << a << endl;
}
};
class B : A{
private:
int b;
public:
virtual void set(int num){
b = num;
}
};
class C : public A, public B{
private:
int c;
public:
void print() const{
cout << c << endl;
}
void set(int num){
c = num;
}
};
И проверить расположение в памяти каждого класса в БГД:
(gdb) p a
$1 = (A) {
_vptr.A = 0x400bb0 <vtable for A+16>,
a = 0
}
(gdb) p b
$2 = (B) {
_vptr.B = 0x400b90 <vtable for B+16>,
b = 4196384
}
(gdb) p c
$3 = (C) {
<A> = {
_vptr.A = 0x400b50 <vtable for C+16>,
a = 4197101
},
<B> = {
_vptr.B = 0x400b70 <vtable for C+48>,
b = 0
},
members of C:
c = 0
}
Это показывает, что есть два vptrs
в классе С. Тогда я компилирую его получить с -fdump-class-hierarchy
, и я получаю некоторую информацию ,
Vtable for A
A::_ZTV1A: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI1A)
16 (int (*)(...))A::print
Class A
size=16 align=8
base size=12 base align=8
A (0x0x7fe4654956c0) 0
vptr=((& A::_ZTV1A) + 16u)
Vtable for B
B::_ZTV1B: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI1B)
16 (int (*)(...))B::set
Class B
size=16 align=8
base size=12 base align=8
B (0x0x7fe465495720) 0
vptr=((& B::_ZTV1B) + 16u)
Vtable for C
C::_ZTV1C: 7u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI1C)
16 (int (*)(...))C::print
24 (int (*)(...))C::set
32 (int (*)(...))-16
40 (int (*)(...))(& _ZTI1C)
48 (int (*)(...))C::_ZThn16_N1C3setEi
Class C
size=32 align=8
base size=32 base align=8
C (0x0x7fe46516e690) 0
vptr=((& C::_ZTV1C) + 16u)
A (0x0x7fe465495780) 0
primary-for C (0x0x7fe46516e690)
B (0x0x7fe4654957e0) 16
vptr=((& C::_ZTV1C) + 48u)
Тогда я смущен следующими вопросами.
Class A size=16 align=8 base size=12 base align=8
Я не понимаю, почему размер класса А 16 и что базовый размер и выровняйте в виду? Я думал, что размер класса A должен быть 12 байтов в случае 8 байтов дляvptr
и 4 байта дляint a
. То же самое для класса B.- Я думал, что есть класс 2
vtables
класса C. Но результат показал только один из 7 записей. какова связь между этимvtable
и двумяvptr
класса C? - Последняя строка показала, что
vptr=((& C::_ZTV1C) + 48u)
, что означает 48? и последней записиvtable
класса C показали, что48 (int (*)(...))C::_ZThn16_N1C3setEi
что это значит? это не имя виртуальных функций, а смещение сверху. почему второйvptr
натолкнулся на эту запись.
относительно вопроса 1, вам нужно взглянуть на прокладку структуры. Ваша арка ПК выравнивается по 16 байт. int занимает 4 байта, а указатель функции на печать занимает 8 байтов, поэтому 12 байт для базового размера, а последние 4 байта предназначены для выравнивания данных. (Https://en.wikipedia.org/wiki/Data_structure_alignment) – lucasg