1. 程式人生 > >13.多重繼承(菱形繼承),虛繼承,虛基類

13.多重繼承(菱形繼承),虛繼承,虛基類

多重繼承:

就是一個派生類多個基類,幾乎與單繼承是一致的。

唯一考點: 菱形繼承結構(B類C類繼承A類,D類繼承A類。),產生問題,派生類有多份基類的資料。   解決辦法:B C都採用虛繼承,只有一個虛繼承也無法解決該問題。

虛繼承:

厲害了,virtual不僅可以宣告虛擬函式,還可以設定繼承方式:虛繼承         

被採用虛繼承的基類 A,稱為虛基類

此時派生類的大小擴大:會有虛基類指標B,C都會產生一個虛基類指標 vbptr(virtual base ptr)。並且如果基類有虛擬函式,所以派生類還會有虛擬函式指標vfptr。

重點:

正常繼承,派生類物件的記憶體先放:   基類物件,再放自己的成員變數。   並且這個是派生類包含

著基類內容 而虛繼承,派生類物件的記憶體先放 :   一個虛基類指標vbptr、和自己的成員變數,之後放基類物件。          這兩個卻是並列存放的。所以A的am就是D自己的了,需要D自己構造

將B,C相同繼承下來的A,放到最後面,在原來的地方會留下虛基類指標。b一個 c一個,還有個虛基類表(第一行 存放的是虛基類指標自己的偏移地址,一般是0. 第二行存放的是,虛基類指標到A成員變數的偏移地址),存放的是A成員變數的偏移量,用這個指標可以找到A的成員變數。

舉個栗子:

class A
{
public:
	A(int data) :ma(data){ cout << "A()" << endl; }
	~A(){ cout << "~A()" << endl; }
protected:
	int ma;
};
////////////////////////////////////////////////////
class B : virtual public A  就在這!!!!!!!!!!!
{
public:
	B(int data) :A(data), mb(data){ cout << "B()" << endl; }
	~B(){ cout << "~B()" << endl; }
protected:
	int mb;
};

class C : virtual public A  就在這!!!!!!!!!!!
{
public:
	C(int data) :A(data), mc(data){ cout << "C()" << endl; }
	~C(){ cout << "~C()" << endl; }
protected:
	int mc;
};
////////////////////////////////////////////////////
class D : public B, public C
{
public:
	D(int data) :md(data),A(data), B(data), C(data)
	{
		cout << "D()" << endl;
	}
	~D(){ cout << "~D()" << endl; }
	void show(){ cout << ma << endl; }
	
protected:
	int md;
};

int main()
{
	cout << sizeof(D) << endl;
	D d(10);
	d.show();

	int *p = (int*)&d;  將B的vbptr地址給了p
	int *q = (int*)*p;  將vbptr解引用也就是B的vbtable。
	q += 1;             +1後就指向了偏移量
	int offset = *q;    記錄姐引用後的偏移量

	char *p1 = (char*)&d;換成char才可以
	p1 += offset;       加上偏移量,之後p1就指向ma
	*(int*)p1 = 30;     更改ma的值

	d.show();

	return 0;
}