C++:虚表指针、虚表、虚函数和动态多态
class Base { public: virtual void show() { std::cout << "Base show" << std::endl; } }; class Derived_1 : public Base { public: void show() override { std::cout << "Derived show" << std::endl; } }; class Derived_2: public Base { public: void show() override { std::cout << "Derived show" << std::endl; } }; Base *b = new Derived_1();
b->show(); Base *c = new Derived_2();
c->show();
分析上面代码,用基指针b指向Derived_1的实例化对象,然后使用b调用Derived的实例化对象重写的虚函数show(),同样的创建另外一个基指针调用DErived_2的实例化对象然后调用其重写的show()
那么有个问题,一样时基类Base的指针,它是怎么知道我此时该调用的是Derive_1中的show()还是Derive_2中的show()?
找一个"地图"用来查询,这个"地图"就放在Derived_1和Derived_2类的里面作为它们的成员之一,上面记录着他们各自内部所有的虚函数地址
当调用
b->show();
时,会访问Derived_1中的"地图",找到属于Derived_1的show()函数的地址,然后执行,c->show();同理。
这里的"地图"就是虚表,虚表是一个指针数组,里面存放着该类所有虚函数的地址。
显然,每个类都有自己不同的虚表,那基类指针b是如何得到对应不同的虚表?
当使用多态指针进行类的实例化时,就会"得到"地图,每个基类内都有个成员,称之为虚表指针,
当执行
Base *b = new Derived_1();
时,b的虚表指针就会初始化为Derived_1实例化对象的虚表地址,或者说指向虚表,这样一来就可以通过虚表指针找到虚表,再进一步找到需要的虚函数
然后就是一个比较重要的问题:为什么必须是指针或者引用才能实现多态?
这里引用一篇博客的实验
简单来说,通过前面的阐述,我们知道多态是通过虚表指针、虚表进行索引查找子类的虚函数,
而赋值方式没办法对多态指针(基类指针)进行初始化,也就是说,以下面这种方式
Base b;
Derived_1 bb;
b = bb;
b内的虚表指针是不会指向bb的虚表,自然无法通过b去调用bb的show函数