多重继承的问题三:
多重继承可能产生多个虚函数表
#include <iostream> using namespace std; class BaseA { public: virtual void funcA() { cout << "BaseA::funcA()" << endl; } }; class BaseB { public: virtual void funcB() { cout << "BaseB::funcB()" << endl; } }; class Derived : public BaseA, public BaseB { }; int main() { Derived d; cout << "sizeof(d)=" << sizeof(d) <<endl; return 0; }
sizeof(d) = 8
相关的三个类中都没有定义成员变量,那这8个字节是从哪来的,谁占用的?
虚函数表指针
在Derived这个类中有两个成员,这两个成员都是虚函数表指针。在创建对象的时候,这两个成员会指向不同的虚函数表
#include <iostream> using namespace std; class BaseA { public: virtual void funcA() { cout << "BaseA::funcA()" << endl; } }; class BaseB { public: virtual void funcB() { cout << "BaseB::funcB()" << endl; } }; class Derived : public BaseA, public BaseB { }; int main() { Derived d; BaseA* pa = &d; BaseB* pb = &d; BaseB* pbb = (BaseB*)pa; cout<< "using pa to call funcA()..." <<endl; pa->funcA(); //对funcA的调用肯定是通过指向虚函数表的指针来完成的 cout << "using pb to call funcB()..." << endl; pb->funcB() //对funcA的调用肯定是通过指向虚函数表的指针来完成的
cout<< "using pbb to call funcB()..." << endl; pbb->funcB(); //这个地方应该打印funcB(),而打印结果是funcA() return 0; }
需要进行强制类型转换时,C++中推荐使用新式类型转换关键字。
解决方案:dynamic_cast
通过pa指针调用funcA的过程:
从pa中得到对象的地址;
通过该地址找到虚函数表指针;
通过虚函数表的指针到虚函数表中去找对应的函数地址。
因此找到的是funcA的地址。
通过pb调用funcB的过程与pa调用funcA的过程是一样的。
通过pbb指针调用funcB的过程:
首先通过pbb得到对象的地址;
然后去找虚函数表指针,找到的虚函数表是vptr1;
去vptr1这个虚函数指针所指的虚函数表中找funcB的地址,在这个地方肯定找不到。找到的是funcA的地址。
原因:原因就是(BaseB* )pa这个地方的强制类型转换是有问题的。在进行强制类型转换时,推荐使用新式类型转换关键字,不要再使用C语言那种暴力的强制转换了
int main() { Derived d; BaseA* pa = &d; BaseB* pb = &d; BaseB* pbb = dynamic_cast<BaseB*>(pa); cout<< "using pa to call funcA()..." <<endl; pa->funcA(); cout << "using pb to call funcB()..." << endl; pb->funcB(); cout<< "using pbb to call funcB()..." << endl; pbb->funcB(); return 0; }
BaseB* pbb = dynamic_cast<BaseB*>(pa);
此时编译器做了什么呢?
由于使用了dynamic_cast这个关键字,编译器就会去做检查,首先编译器就会检查pa这个对象所指向的对象是什么,发现是d对象。
进而编译器会去看d对象它有哪些父类呢?发现有BaseA和BaseB,然后编译器就会认为这个地方进行的强制类型转换是合法的,那又会怎样呢?编译器在强制类型转换的时候就会对指针有一个修正的过程。使得pbb指向pb所指的位置。
int main() { Derived d; BaseA* pa = &d; BaseB* pb = &d; BaseB* pbb = dynamic_cast<BaseB*>(pa); BaseB* pbc = (BaseB*)pa; cout<< "using pa to call funcA()..." <<endl; pa->funcA(); cout << "using pb to call funcB()..." << endl; pb->funcB(); cout<< "using pbb to call funcB()..." << endl; pbb->funcB(); cout << "pa=" << pa <<endl; cout << "pb=" << pb << endl; cout << "pbb=" << pbb << endl; cout << "pbc=" << pbc << endl; return 0; }
原文地址:https://www.cnblogs.com/-glb/p/11967935.html