C++ - 多继承方式会产生多个虚函数表
1.多重繼承可能產生多個虛函數表
代碼示例:會產生多個虛函數表
#include <iostream> #include <string>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; //pa->BaseABaseB* pb = &d; //pb->BaseBBaseB* pbe = (BaseB*)pa; // oops!!指向了A的虛函數表(重點在這里)BaseB* pbc = dynamic_cast<BaseB*>(pa); //指向了B的虛函數表cout << "sizeof(d) = " << sizeof(d) << endl; //8,兩個指針,指向虛函數表cout << "Using pa to call funcA()..." << endl;pa->funcA(); //BaseA::funcA()cout << "Using pb to call funcB()..." << endl;pb->funcB(); //BaseB::funcB()cout << "Using pbc to call funcB()..." << endl;pbc->funcB(); //BaseB::funcB()cout << endl;cout << "pa = " << pa << endl; //假設:Acout << "pb = " << pb << endl; //假設:Bcout << "pbe = " << pbe << endl; cout << "pbc = " << pbc << endl;return 0; }?結果:
sizeof(d) = 8 Using pa to call funcA()... BaseA::funcA() Using pb to call funcB()... BaseB::funcB() Using pbc to call funcB()... BaseB::funcB()pa = 0xbf9d2558 pb = 0xbf9d255c pbe = 0xbf9d2558 pbc = 0xbf9d255c分析:
?強制轉換后(Base* pbb = (Base*)pa),pbb是BaseB類型,應該指向vptr2的虛函數表,但卻指向了vptr1的虛函數表?。
這時需要進行強制類型轉換時,C++中推薦使用新式類型轉換關鍵字(dynamic_cast)!!,BaseB* pbc = dynamic_cast<BaseB*>(pa),指向了B的虛函數表。
2.正確的使用多重繼承
代碼示例:
#include <iostream> #include <string>using namespace std;class Base { protected:int mi; public:Base(int i){mi = i;}int getI(){return mi;}bool equal(Base* obj) //為了判斷參數指針,是不是指向當前對象{return (this == obj);} };class Interface1 { public:virtual void add(int i) = 0;virtual void minus(int i) = 0; //減法 };class Interface2 { public:virtual void multiply(int i) = 0;virtual void divide(int i) = 0; };//單繼承父類+多個接口 class Derived : public Base, public Interface1, public Interface2 { public:Derived(int i) : Base(i) //構造函數{}void add(int i){mi += i;}void minus(int i){mi -= i;}void multiply(int i){mi *= i;}void divide(int i){if( i != 0 ) //分母不為0{mi /= i;}} };int main() {Derived d(100); //定義類,主要是為了初始化父類中數據cout << sizeof(d) << endl; //12Derived* p = &d; Interface1* pInt1 = &d; //目的,獲取d的數據和函數(加減)Interface2* pInt2 = &d; //目的,獲取d的數據和函數(乘除)cout << "&d = " << &d << endl;cout << "pInt1 = " << pInt1 << endl;cout << "pInt2 = " << pInt2 << endl;//父類cout << "p->getI() = " << p->getI() << endl; // 100pInt1->add(10); //100+10 = 110pInt2->divide(11); //110/11 = 10pInt1->minus(5); //10-5 = 5pInt2->multiply(8); //5*8 = 40//父類cout << "p->getI() = " << p->getI() << endl; // 40cout << endl;//為了判斷pInt1和pInt2指針,與p指針是不是指向同一個對象cout << "pInt1 == p : " << p->equal(dynamic_cast<Base*>(pInt1)) << endl;cout << "pInt2 == p : " << p->equal(dynamic_cast<Base*>(pInt2)) << endl;return 0; }結果:
12 &d = 0xbfd5b934 pInt1 = 0xbfd5b934 pInt2 = 0xbfd5b93c p->getI() = 100 p->getI() = 40this = 0xbfd5b938 obj = 0xbfd5b938 pInt1 == p :1 this = 0xbfd5b938 obj = 0xbfd5b938 pInt2 == p :1分析:
打印12,除了int mi占用4字節,還繼承了2個接口產生2個虛函數表指針,導致內存占用12,一個類中有2個虛函數,但卻只有一個接口產生一個虛擬函數表,有一個指針是指向了虛函數表,一個指針占用4字節,2個類中的虛函數表就2個指針占用8字節。
多繼承的方式也一樣,子類與父類的同名函數,父類是虛函數,子類也是虛函數,子類的同名函數會覆蓋父類的同名函數。
一些有用的工程建議:
-> 先繼承自一個父類,然后實現多個接口。
-> 父類中提供equal()成員函數。
-> equal()成員函數用于判斷指針是否指向當前對象。
-> 與多重繼承相關的強制類型轉換用dynamic_cast完成。
小結:
-> 多繼承中可能出現多個虛函數表指針。
-> 與多重繼承相關的強制類型轉換用dynamic_cast完成。
-> 工程開發中采用“單繼承多接口”的方式使用多繼承。
-> 父類提供成員函數用于判斷指針是否指向當前對象。
總結
以上是生活随笔為你收集整理的C++ - 多继承方式会产生多个虚函数表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编程语言只是一个工具
- 下一篇: 日语在线翻译excite网页版