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環境下用的是偏移量,而不是圖中的直接指針指向這里只是為了更直觀的展示。