在您发布的示例中,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)。这些负责设置 vtables(_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 的内容基本相同。