C++ 多态底层实现原理详解
在讨论多态的语法层面(如虚函数、override、final)之后,很多开发者对底层的运行机制仍有疑问:为什么带虚函数的类 sizeof 会变大?基类指针如何找到派生类的函数?虚表存在哪里?本文将从内存布局、对象模型及汇编视角,彻底剖析 C++ 多态的实现机制。
一、虚函数与普通函数的区别
我们可以通过一个简单的内存大小测试来切入。考虑以下代码:
class Base {
public:
virtual void Func1() {
cout << "Func1()" << endl;
}
protected:
int _b = 1;
char _ch = 'x';
};
int main() {
Base b;
cout << sizeof(b) << endl;
return 0;
}
对于普通类,成员函数不占用对象内存空间,仅数据成员计入大小。上述类中 _b 占 4 字节,_ch 占 1 字节,按内存对齐后通常为 8 字节。但实际运行结果为 12 字节。
这是因为编译器在含有虚函数的类对象中插入了一个隐藏的指针,称为虚函数表指针(vptr)。每个含虚函数的类对象至少包含一个 vptr,用于指向该类的虚函数表(vtable)。这个指针的大小取决于系统架构(32 位为 4 字节,64 位为 8 字节),正是它导致了对象大小的增加。
二、多态的实现原理
1. 动态绑定机制
多态的核心在于运行时决定调用哪个函数。当通过基类指针或引用调用虚函数时,编译器不会直接生成函数地址,而是生成一段查找逻辑:
- 通过对象中的 vptr 找到虚函数表。
- 根据虚函数在表中的偏移量获取函数地址。
- 跳转到该地址执行。
这意味着,虽然指针类型是基类,但实际调用的函数取决于指针当前指向的对象类型。
class Person {
public:
virtual void BuyTicket() {
cout << "买票 - 全价" << endl;
}
private:
string _name;
};
class : Person {
:
{
cout << << endl;
}
:
string _id;
};
: Person {
:
{
cout << << endl;
}
:
string _codename;
};
{
ptr->();
}
{
Person ps;
Student st;
Soldier sr;
(&ps);
(&st);
(&sr);
;
}


