C++虚函数、虚函数表、多态的深入理解
大家都知道多态发生需要:
- 要有继承
- 要有虚函数重写
- 父类指针指向子类对象
那么c++底层是如何实现多态这个骚操作的呢,接下来我谈谈自己的看法:
首先定义两个类:
class fruit {
public:
int f;
fruit(int fi) { f = fi; };
virtual void show() {
cout << "I am fruit" << endl;
}
};
class apple : public fruit {
public:
apple(int i) : fruit(i) {};
virtual void show() {
cout << "I am apple" << endl;
}
};
我们定义两个类的对象:
int main() {
fruit f1(1);
apple a(2);
system("pause");
return 0;
}
他们的实际内存模型是这样的:
对象f1和对象a的内存模型中会有一个指向虚函数表的指针,就是一个4字节内存块(32位平台下),指针指向一块内存,该内存块中存储的就是函数指针。不进行虚函数重写,那么对象a的虚函数表就和对象f一样,但如果进行了重写,虚函数表中的函数指针指向的就是对象a自己实现的show()函数。
接下来验证底层是否是这样实现的:
用visio studio观察对象:
可以看到对象中确实多了_Vfptr的变量,它就是指向虚函数表的指针。那么虚函数表中的指针是否就是指向对象a中show()的函数呢?考虑以下代码:
typedef void(*func)(); // 函数指针类型 别名func
int main() {
fruit f1(1);
apple a(2);
fruit* f2 = &a;
f2->show(); // 多态的使用
// 底层实现模拟 类似把上面的函数调用翻译成下面的实现
int* p = (int*)(&a); // 取出虚函数表指针
cout << hex << *p << endl;
func pf = (func)*((int*)(*p)); // 函数指针
//func pf = (func)(((int64_t*)(*p))[0]); // 等效为上一句
cout << hex << *pf << endl;
pf(); // 执行函数 效果和f2->show()一样
system("pause");
return 0;
}
当执行f2->show()时,取出了对象a的虚函数表然后根据调用的函数执行相应的函数。