C++ - 多继承方式会产生多个虚函数表
1.多重繼承可能產(chǎn)生多個虛函數(shù)表
代碼示例:會產(chǎn)生多個虛函數(shù)表
#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的虛函數(shù)表(重點在這里)BaseB* pbc = dynamic_cast<BaseB*>(pa); //指向了B的虛函數(shù)表cout << "sizeof(d) = " << sizeof(d) << endl; //8,兩個指針,指向虛函數(shù)表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; //假設(shè):Acout << "pb = " << pb << endl; //假設(shè):Bcout << "pbe = " << pbe << endl; cout << "pbc = " << pbc << endl;return 0; }?結(jié)果:
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分析:
?強制轉(zhuǎn)換后(Base* pbb = (Base*)pa),pbb是BaseB類型,應(yīng)該指向vptr2的虛函數(shù)表,但卻指向了vptr1的虛函數(shù)表?。
這時需要進行強制類型轉(zhuǎn)換時,C++中推薦使用新式類型轉(zhuǎn)換關(guān)鍵字(dynamic_cast)!!,BaseB* pbc = dynamic_cast<BaseB*>(pa),指向了B的虛函數(shù)表。
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) //為了判斷參數(shù)指針,是不是指向當前對象{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) //構(gòu)造函數(shù){}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); //定義類,主要是為了初始化父類中數(shù)據(jù)cout << sizeof(d) << endl; //12Derived* p = &d; Interface1* pInt1 = &d; //目的,獲取d的數(shù)據(jù)和函數(shù)(加減)Interface2* pInt2 = &d; //目的,獲取d的數(shù)據(jù)和函數(shù)(乘除)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; }結(jié)果:
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字節(jié),還繼承了2個接口產(chǎn)生2個虛函數(shù)表指針,導致內(nèi)存占用12,一個類中有2個虛函數(shù),但卻只有一個接口產(chǎn)生一個虛擬函數(shù)表,有一個指針是指向了虛函數(shù)表,一個指針占用4字節(jié),2個類中的虛函數(shù)表就2個指針占用8字節(jié)。
多繼承的方式也一樣,子類與父類的同名函數(shù),父類是虛函數(shù),子類也是虛函數(shù),子類的同名函數(shù)會覆蓋父類的同名函數(shù)。
一些有用的工程建議:
-> 先繼承自一個父類,然后實現(xiàn)多個接口。
-> 父類中提供equal()成員函數(shù)。
-> equal()成員函數(shù)用于判斷指針是否指向當前對象。
-> 與多重繼承相關(guān)的強制類型轉(zhuǎn)換用dynamic_cast完成。
小結(jié):
-> 多繼承中可能出現(xiàn)多個虛函數(shù)表指針。
-> 與多重繼承相關(guān)的強制類型轉(zhuǎn)換用dynamic_cast完成。
-> 工程開發(fā)中采用“單繼承多接口”的方式使用多繼承。
-> 父類提供成員函數(shù)用于判斷指針是否指向當前對象。
總結(jié)
以上是生活随笔為你收集整理的C++ - 多继承方式会产生多个虚函数表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编程语言只是一个工具
- 下一篇: c++虚函数详解(你肯定懂了)