[C++基礎]虛繼承實現原理

在C++中,我們會遇到virtual這個關鍵字,但是它有兩種含義:虛函數和虛繼承,它們兩個是完全無相關的兩個概念。

什麼是虛繼承  

虛繼承是解決C++多重繼承問題的一種手段,從不同途徑繼承來的同一基類,會在子類中存在多份拷貝。這將存在兩個問題:其一,浪費存儲空間;第二,存在二義性問題通常可以將派生類對象的地址賦值給基類對象,實現的具體方式是,將基類指針指向繼承類(繼承類有基類的拷貝)中的基類對象的地址,但是多重繼承可能存在一個基類的多份拷貝,這就出現了二義性。

當一個基類被聲明爲虛基類後,即使它成爲了多繼承鏈路上的公共基類,最後的派生類中也只有它的一個備份。例如:

class CBase { };
class CDerive1:virtual public CBase{ };
class CDerive2:virtual public CBase{ };
class CDerive12:public CDerive1,CDerive2{ };

則在類CDerive12的對象中,僅有類CBase的一個對象數據

虛繼承實現原理

虛繼承底層實現原理與編譯器相關,一般通過虛基類指針和虛基類表實現,每個虛繼承的子類都有一個虛基類指針(任何類型的指針變量都是佔用4個字節)和虛基類表(不佔用類對象的存儲空間)(需要強調的是,虛基類依舊會在子類裏面存在拷貝,只是僅僅最多存在一份而已,並不是不在子類裏面了);當虛繼承的子類被當做父類繼承時,虛基類指針也會被繼承。
實際上,vbptr指的是虛基類表指針,該指針指向了一個虛基類表,虛表中記錄了虛基類與本類的偏移地址;通過偏移地址,這樣就找到了虛基類成員,而虛繼承也不用像普通多繼承那樣維持着公共基類(虛基類)的兩份同樣的拷貝,節省了存儲空間。

虛繼承與虛函數的異同

相似之處:都利用了虛指針(均佔用類的存儲空間)和虛表(均不佔用類的存儲空間)。
不同之處:虛基類依舊存在繼承類中,只佔用存儲空間;虛函數不佔用存儲空間。虛基類表存儲的是虛基類相對直接繼承類的偏移而虛函數表存儲的是虛函數地址

#include<iostream>  
using namespace std;

class A  //大小爲4  
{
public:
	int a;
};
class B :virtual public A  //大小爲12,變量a,b共8字節,虛基類表指針4  
{
public:
	int b;
};
class C :virtual public A //與B一樣12  
{
public:
	int c;
};
class D :public B, public C //24,變量a,b,c,d共16,B的虛基類指針4,C的虛基類指針  
{
public:
	int d;
};

int main()
{
	A a;
	B b;
	C c;
	D d;
	cout << sizeof(a) << endl;
	cout << sizeof(b) << endl;
	cout << sizeof(c) << endl;
	cout << sizeof(d) << endl;
	system("pause");
	return 0;
}
//
//1 > class A	size(4) :
//1 > +-- -
//1 > 0 | a
//1 > +-- -
//1 >
//1 > class B	size(12) :
//1 > +-- -
//1 > 0 | {vbptr}
//1 > 4 | b
//1 > +-- -
//1 > +-- - (virtual base A)
//1 > 8 | a
//1 > +-- -
//1 >
//1 > B::$vbtable@:
//1 > 0 | 0
//1 > 1 | 8 (Bd(B + 0)A)
//1 > vbi:class  offset o.vbptr  o.vbte fVtorDisp
//1 >         A       8       0       4 0
//1 >
//1 > class C	size(12) :
//1 > +-- -
//1 > 0 | {vbptr}
//1 > 4 | c
//1 > +-- -
//1 > +-- - (virtual base A)
//1 > 8 | a
//1 > +-- -
//1 >
//1 > C::$vbtable@:
//1 > 0 | 0
//1 > 1 | 8 (Cd(C + 0)A)
//1 > vbi:class  offset o.vbptr  o.vbte fVtorDisp
//1 >         A       8       0       4 0
//1 >
//1 > class D	size(24) :
//1 > +-- -
//1 > 0 | +-- - (base class B)
//1 > 0	| | {vbptr}
//1 > 4	| | b
//1 > | +-- -
//1 > 8 | +-- - (base class C)
//1 > 8	| | {vbptr}
//1 > 12	| | c
//1 > | +-- -
//1 > 16 | d
//1 > +-- -
//1 > +-- - (virtual base A)
//1 > 20 | a
//1 > +-- -
//1 >
//1 > D::$vbtable@B@:
//1 > 0 | 0
//1 > 1 | 20 (Dd(B + 0)A)
//1 >
//1 > D::$vbtable@C@:
//1 > 0 | 0
//1 > 1 | 12 (Dd(C + 0)A)
//1 > vbi:class  offset o.vbptr  o.vbte fVtorDisp
//1 >         A      20       0       4 0
//1 >

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章