C++虚函数详解:内存布局与实现机制

0 下载量 88 浏览量 更新于2024-08-31 收藏 360KB PDF 举报
本文将深入浅出地探讨C++中的虚函数机制,尤其针对VS2013生成的32位代码进行讲解。首先,我们回顾了一个示例,其中`CBase`类定义了两个虚函数`VFun1`和`VFun2`,以及一个数据成员`data`。当创建`CDerived`类的对象并将其赋值给`CBase`类型的指针`pBase`时,调用`VFun1`和`VFun2`产生了意外的输出结果,因为内存布局发生了变化。 在C++中,当一个类包含虚函数时,编译器会在每个对象的存储空间头部自动添加一个虚函数表(Virtual Function Table,简称VTable)。这个VTable是一个动态链接表,用于存储该类及其所有基类的所有虚函数的地址。每个VTable项代表一个虚函数,索引由虚函数在基类继承链上的位置决定,-1通常表示终止符或未定义。 在`CDerived`类继承自`CBase`后,`CBase`类的VTable会包含`VFun1`、`VFun2`和析构函数,而`CDerived`类自己的虚函数`VFunNew`、`VFun1`和析构函数也会被添加到VTable中。由于`CDerived`重写了`VFun1`,所以它的地址会取代`CBase`类中的`VFun1`位置。 当我们创建`CDerived`对象并将其赋值给`CBase`指针时,实际上`pBase`指向的是`CDerived`对象的地址,而不是`CBase`对象的地址。因此,`pBase->VFun1()`实际上是调用了`CDerived`类中的`VFun1`,而不是`CBase`的版本。这就是为何输出结果显示`VFun1`而不是`CBase::VFun1`的原因。 `CDerived`对象的内存布局包含了`CBase`的虚函数表指针,以及`data`成员,它们的相对位置由编译器决定,通常数据成员紧跟在基类的VTable之后,以保持对象的紧凑性。至于为什么`offsetof(CBase, data)`的结果是4,这是因为`data`位于VTable之后,而VTable占4字节,所以两者之间的偏移是4。 总结来说,C++的虚函数实现涉及动态链接表——虚函数表,它使得子类对象能够根据实际类型调用正确的函数,即便通过基类指针。理解内存布局对于调试和优化C++程序至关重要,尤其是处理多态行为时。通过这个实例,我们可以看到C++的运行时多态性和底层机制是如何协同工作的。