C++中的類繼承之單繼承&多繼承&菱形繼承
單繼承是一般的單一繼承,一個子類只 有一個直接父類時稱這個繼承關系為單繼承。這種關系比較簡單是一對一的關系:
多繼承是指 一個子類有兩個或以上直接父類時稱這個繼承關系為多繼承。這種繼承方式使一個子類可以繼承多個父類的特性。多繼承可以看作是單繼承的擴展。派生類具有多個基類,派生類與每個基類之間的關系仍可看作是一個單繼承。多繼承下派生類的構造函數與單繼承下派生類構造函數相似,它必須同時負責該派生類所有基類構造函數的調用。同時,派生類的參數個數必須包含完成所有基類初始化所需的參數個數。在子類的內存中它們是按照聲明定義的順序存放的,下面的截圖將清晰看到。
但是多繼承存在一個問題,要想研究這個問題,我們先從單繼承講起。來看內存空間:
class Base
{
public:
Base() {
cout << "B()" << endl;
}
int b1;
};
class Derive : public Base
{
public:
Derive() {
cout << "D()" << endl;
}
int d1;
};
int main()
{
Test();
getchar();
return 0;
}

多繼承的內存空間:
class Base
{
public:
Base() {
cout << "B()" << endl;
}
int b1;
};
class C
{
public:
C() {
cout << "C()" << endl;
}
int c;
};
class Derive : public Base, public C
{
public:
Derive() {
cout << "D()" << endl;
}
int d1;
};
菱形繼承內存中數據分布:
class A
{
public:
A() {
cout << "A()" << endl;
}
int a;
};
class Base:public A
{
public:
Base() {
cout << "B()" << endl;
}
int b1;
};
class C: public A
{
public:
C() {
cout << "C()" << endl;
}
int c;
};
class Derive : public Base, public C
{
public:
Derive() {
cout << "D()" << endl;
}
int d1;
};
在A類中初始化int a=4則可清楚的看到菱形繼承中內存分布
所以子類Derive中有兩份A類中的數據成員,這造成了訪問二義性和數據冗余的問題
這就是我前面說的多繼承存在的問題。可以這樣訪問
1 tmp.C::a=4; 2 tmp.Base::a=5;
什么是對象模型
有兩個概念可以解釋C++對象模型:
1、語言中直接支持面向對象程序設計的部分。
2、對於各種支持的底層實現機制。

還有另外一個方法解決這個問題,我們要用到一種新的繼承方法:虛繼承--解決菱形繼承的二義性和數據冗余的問題。看下面這段代碼:
1 class Base
2 {
3 public:
4 Base() {
5 cout << "B()" << endl;
6 }
7 int b1;
8 };
9 class Derive : virtual public Base
10 {
11 public:
12 Derive() {
13 cout << "D()" << endl;
14 }
15 int d1;
16 };
17 void Test()
18 {
19 Derive tmp;
20 tmp.d1 = 1;
21 tmp.b1 = 2;
23 }
24 int main()
25 {
26 Test();
27 getchar();
28 return 0;
29 }
虛擬繼承的關鍵字---virtual
1 class A
2 {
3 public:
4 A() {
5 cout << "A()" << endl;
6 }
7 int a ;
8 };
9 class Base : virtual public A
10 {
11 public:
12 Base() {
13 cout << "B()" << endl;
14 }
15 int b1;
16 };
17 class C:virtual public A
18 {
19 public:
20 C() {
21 cout << "C()" << endl;
22 }
23 int c;
24 };
25 class Derive : virtual public Base, virtual public C
26 {
27 public:
28 Derive() {
29 cout << "D()" << endl;
30 }
31 int d1;
32 };
33 void Test()
34 {
35 Derive tmp;
36 tmp.d1 = 1;
37 tmp.b1 = 2;
38 tmp.c = 3;
39 tmp.a = 4;
40 }
41 int main()
42 {
43 Test();
44 getchar();
45 return 0;
46 }


菱形虛擬繼承的對象模型
解決二義性問題在vs環境下用的是偏移量,而不是圖中的直接指針指向這里只是為了更直觀的展示。

