В примере, который вы разместили, GCC по умолчанию полностью оптимизирует vtable. Поскольку это только одна единица перевода и все видно, это возможно.
Я изменил ваш пример на:
#include <iostream>
using namespace std;
class Z
{
public:
int a;
virtual void x () const {}
};
class Y : public Z
{
public:
int a;
};
int main()
{
Y y;
const Z& z1=y;
const Z& z2=Z();
z1.x(),z2.x();
cout << "\nZ: " << sizeof (Z);
cout << "\nY: " << sizeof (Y);
}
В этом случае vtable генерируется на выходе:
nm a.out|c++filt|grep -i vtable
08048880 V vtable for Y
08048890 V vtable for Z
0804a040 V vtable for __cxxabiv1::__class_type_info@@CXXABI_1.3
0804a120 V vtable for __cxxabiv1::__si_class_type_info@@CXXABI_1.3
Если мы сгенерируем сборку с -S
, тогда мы сможем найти конструкторы (искаженные как _ZN1ZC2Ev
и _ZN1YC2Ev
соответственно в моей системе). Они занимаются настройкой виртуальных таблиц (_ZTV1Z
и _ZTV1Y
):
Конструктор для Z
:
_ZN1ZC2Ev:
.LFB970:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 8(%ebp), %eax
movl $_ZTV1Z+8, (%eax)
popl %ebp
.cfi_def_cfa 4, 4
.cfi_restore 5
ret
А Y
:
_ZN1YC2Ev:
.LFB972:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $24, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call _ZN1ZC2Ev
movl 8(%ebp), %eax
movl $_ZTV1Y+8, (%eax)
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
Интересно то, что то, что помещается в vtable в обоих конструкторах, по сути одинаково.