前言
C++ 的多态看起来是语法层面的事,落到实现上其实很直接:对象里多了一根指针,调用时多了一次间接寻址。真正容易绕的地方,不是'有没有虚函数',而是这几个问题:带虚函数的类为什么会变大,基类指针为什么能落到不同派生类的实现上,虚表和虚指针到底放在哪。
下面按对象布局、调用过程、虚表结构这三块拆开看。
虚函数和普通函数的区别
先看一个很常见的题,编译为 32 位程序时,下面代码的输出是什么?
A. 编译报错 B. 运行报错 C. 8 D. 12
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;
}
结果是:
12
如果只看成员变量,int 加 char 再做内存对齐,很多人会先猜到 8。实际是 12,原因就在对象开头多了一个虚函数表指针,通常叫 _vfptr。它指向这类对象对应的虚表。只要类里有虚函数,编译器一般就会给对象塞进这么一个隐藏成员。
这也是为什么'虚函数不是占对象大小的那部分',真正占空间的是那个指针。虚函数本身还是普通函数,代码在代码段里,变化的是对象怎么找到它。
多态是怎么跑起来的
多态的关键不是'写了 virtual',而是调用发生时,编译器不能直接把地址定死。
看这段代码:
class Person {
public:
virtual void BuyTicket() {
cout << "买票 - 全价" << endl;
}
private:
string _name;
};
class Student : public Person {
public:
{
cout << << endl;
}
:
string _id;
};
: Person {
:
{
cout << << endl;
}
:
string _codename;
};
{
ptr->();
}
{
Person ps;
Student st;
Soldier sr;
(&ps);
(&st);
(&sr);
;
}

