C++: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;
}

附一篇博客從內存佈局看虛基類,挺詳細的:https://blog.csdn.net/xiejingfa/article/details/48028491

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