class Car{public: virtual void func1() { cout << "Car::func1()" << endl; } virtual void func2() { cout << "Car::func2()" << endl; }PRotected: int _c;//種類};class Bike :public Car{public: virtual void func1() { cout << "Bike::func1()" << endl; } virtual void func2() { cout << "Bike::func2()" << endl; } virtual void func3() { cout << "Bike::func3()" << endl; }protected: int _b;//自行車數(shù)量};int main(){ Car c; Bike b; system("pause"); return 0;}通過這種表我們對單繼承有個初步的了解,可以看道派生類Bike::func1重寫(覆蓋)了父類Car::func1,覆蓋了虛表函數(shù)的位置。但是我們細(xì)心發(fā)現(xiàn),派生類Bike::func3消失了。我們可以打印函數(shù)的地址打開內(nèi)存看個究竟:
class Car{public: virtual void func1() { cout << "Car::func1()" << endl; } virtual void func2() { cout << "Car::func2()" << endl; }protected: int _c;//種類};class Bike :public Car{public: virtual void func1() { cout << "Bike::func1()" << endl; } virtual void func2() { cout << "Bike::func2()" << endl; } virtual void func3() { cout << "Bike::func3()" << endl; }protected: int _b;//自行車數(shù)量};typedef void(*FUNC) ();void PrintfVtable(void *_vfptr){ int *Vtable = (int *)_vfptr; printf("虛表的地址Vtable:0x%x/n",Vtable); for (size_t i = 0; Vtable[i] != 0; ++i) { printf("第%d個虛函數(shù)的地址:0x%x/n", i, Vtable[i]); FUNC f = (FUNC)Vtable[i]; f(); }}int main(){ Car c; Bike b; int *Vtable1 = (int*)(*((int*)&c)); int *Vtable2 = (int*)(*((int*)&b)); PrintfVtable(Vtable1); PrintfVtable(Vtable2); system("pause"); return 0;}我們畫一下它的對象模型:
三.菱形對象
class AA{public: virtual void fun1() { cout << "AA::fun1()" << endl; } virtual void funA() { cout << "AA::funA()" << endl; }public: int _aa;};class BB :public AA{public: virtual void fun1() { cout << "BB::funB()" << endl; } virtual void funB() { cout << "BB::funB()" << endl; }public: int _bb;};class CC :public AA{public: virtual void fun1() { cout << "CC::fun1()" << endl; } virtual void funC() { cout << "CC::funC()" << endl; }public: int _cc;};class DD :public BB,public CC{public: virtual void fun1() { cout << "DD::fun1()" << endl; } virtual void funD() { cout << "DD::funD()" << endl; }public: int _dd;};typedef void(*FUNC)();void PrintfVtable(void *_vfptr){ int*Vtable = (int *)_vfptr; printf("虛表的地址Vtable:0x%x/n",Vtable); for (size_t i = 0; Vtable[i] != 0; ++i) { printf("第%d個虛函數(shù)的地址:0x%x/n", i, Vtable[i]); FUNC f = (FUNC)Vtable[i]; f(); } }int main(){ DD d; d.BB::_aa = 0; d.CC::_aa = 1; d._bb = 2; d._cc = 3; d._dd = 4; int *Vtable1 = (int*)(*((int*)&d)); PrintfVtable(Vtable1); system("pause"); return 0;}通過上面我們很清楚的看到有兩個虛表分別存放虛函數(shù)的地址,第一個存放派生類DD::fun1()的地址和AA::funA();第二個虛函數(shù)存放AA::funA()的地址。這里面就出現(xiàn)菱形繼承的問題二義性和數(shù)據(jù)的冗余的問題。通過觀察內(nèi)存看到。
三.菱形虛擬繼承
在public前面加上關(guān)鍵字virtual:class AA{public: virtual void fun1() { cout << "AA::fun1()" << endl; } virtual void funA() { cout << "AA::funA()" << endl; }public: int _aa;};class BB :virtual public AA{public: virtual void fun1() { cout << "BB::funB()" << endl; } virtual void funB() { cout << "BB::funB()" << endl; }public: int _bb;};class CC :virtual public AA{public: virtual void fun1() { cout << "CC::fun1()" << endl; } virtual void funC() { cout << "CC::funC()" << endl; }public: int _cc;};class DD :public BB,public CC{public: virtual void fun1() { cout << "DD::fun1()" << endl; } virtual void funD() { cout << "DD::funD()" << endl; }public: int _dd;};typedef void(*FUNC)();void PrintfVtable(void* _vptr){ int *Vtable = (int*)_vptr; printf("虛表的地址)0x%x/n", Vtable); for (size_t i = 0; Vtable[i] != 0; ++i) { printf("第%d個虛函數(shù)的地址:0x%x/n", i, Vtable[i]); FUNC f = (FUNC)Vtable[i]; f(); } }int main(){ DD d; d.BB::_aa = 0; d.CC::_aa = 1; d._bb = 2; d._cc = 3; d._dd = 4; int *Vtable = (int*)(*((int*)&d)); PrintfVtable(Vtable); system("pause"); return 0;}前面我們也知道菱形繼承就是多繼承的一種,看到上面也發(fā)現(xiàn)多繼承與單繼承的區(qū)別,至于多繼承的模型我們下次繼續(xù)。。。
|
新聞熱點
疑難解答
圖片精選