C++學習大綱:多繼承


C++學習大綱:多繼承

C++ 多繼承

1. 定義格式

class : [] , [] ,...

{

};

2. 重複繼承——虛基類

在多繼承中,如果直接基類有公共的基類,則會出現重複繼承。這樣,公共基類中的數據成員在多繼承的派生類中皆有多個拷貝。

如:

class A

{

int x;

};

class B: public A{};

class C: public A{};

class D: public B, public C{};

//此時D用有兩個x成員B::x 和 C::x

為了解決這樣的問題,要使用虛基類。

1)虛基類的構造函數有最新派生出的類的構造函數調用

2)虛基類的構造函數優先非虛基類的構造函數執行

class A

{

int x;

public:

A(int i) {x=i;}

};

class B: virtual public A

{

int y;

public:

B(int i): A(1) {y=i;}

};

class C: virtual public A

{

int z;

public:

C(int i): A(2) {z=i;}

};

class D: public B, public C

{

int m;

public:

D(int i, int j, int k): B(i),C(j),A(3){m=k;}

};

class E: public C

{

int n;

public:

E(int i, int j, int k, int l): D(i,j,k),A(4){n=1;}

}; D d(1,2,3); E e(1,2,3,4);

當創建D對象d時,所調用的構造函數的順序是:

A(3), B(1), C(2), D(1,2,3);

當創建E對象e時,所調用的構造函數的順序是:

A(4), B(1), C(2), D(1,2,3), E(1,2,3,4)

————————————————

C++學習大綱:多繼承

C++多繼承詳解

在C++語言中,一個派生類可以從一個基類派生,也可以從多個基類派生。從一個基類派生的繼承稱為單繼承;從多個基類派生的繼承稱為多繼承。

1.繼承的三種方式

公有繼承(public),私有繼承(private),保護繼承(protected)

三種繼承方式的說明,如下表所示:

C++學習大綱:多繼承

2.什麼是多繼承

一個類有多個基類,那麼這種繼承關係就叫做多繼承。 比如有兩個類,服務員類Waiter,歌手類Singer,我們有一個類既是服務員,又是歌手, 那麼我們可以定義類的多繼承關係如下:

<code>class Waiter
{};
class Singer
{};
class SingerWaiter:public Waiter,public Singer
{};/<code>

3.使用多繼承會帶來哪些問題

多繼承比單繼承複雜,也更容易出現問題,因此我們不建議使用多繼承。 多繼承的兩個主要問題是: 1)從兩個不同的基類,繼承同名方法 如下例所示:

<code>class Waiter
{
public:
void work(){std::cout<};
class Singer
{
public:
void work(){std::cout<};
class SingerWaiter:public Waiter,public Singer
{};
int main()
{
SingerWaiter singerWaiter;
singerWaiter.work();
return 0;
}/<code>

編譯器不知道該調用哪個基類的work方法,所以會報singerWaiter.work();不明確錯誤。

2)從多個基類間接繼承同一個類的多個實例 如下例所示:

<code>class Worker
{};
class Waiter:public Worker
{};
class Singer:public Worker
{};
class SingerWaiter:public Waiter,public Singer
{};
int main()
{
SingerWaiter singerWaiter;
Worker *pw = &singerWaiter;
return 0;
}/<code>

會報錯Worker *pw = &singerWaiter;基類Worker不明確。 這是因為SingerWaiter對象創建時,會分別調用Waiter類和Singer類的構造函數, Waiter類和Singer類又會分別調用Worker類的構造函數,生成了兩份Worker類的實例, 所以pw指針,不知道該指向哪一份Worker實例。

4.如何解決多繼承帶來的問題

對於問題一,我們在調用時,需要明確指出具體要調用哪個類的方法,如下所示:

<code>int main()
{
SingerWaiter singerWaiter;
singerWaiter.Waiter::work();//調用Waiter類的方法 singerWaiter.Singer::work();//調用Singer類的方法 return 0;
}/<code>

對於問題二,我們引入了虛基類的概念。如下所示:

<code>class Worker
{};
class Waiter:virtual public Worker
{};
class Singer:virtual public Worker
{};
class SingerWaiter:public Waiter,public Singer
{};
int main()
{
SingerWaiter singerWaiter;
Worker *pw = &singerWaiter;
return 0;
}/<code>

我們在子類繼承時,聲明一個virtual關鍵字,這時,就表明基類Worker是一個虛基類。 實例化SingerWaiter時產生的Waiter對象和Singer對象,共享一個基類Worker對象。

5.使用虛基類需要注意的問題

我們知道繼承關係中,類的構造函數具有傳遞性,如以下代碼所示:

<code>class A
{
private:
int a;
public:
A(int n=0):a(n){}
int get(){return a;}
};
class B:public A
{
private:
int b;
public:
B(int m=0,int n=0):A(n),b(m){}
int get(){return b;}
};
class C:public B
{
private:
int c;

public:
C(int q=0,int m=0,int n=0):B(m,n),c(q){}
int get(){return c;}
void Show()
{
std::cout<<:get> }
};
int main()
{
C c(1,2,3);
c.Show();
return 0;
}/<code>

輸出結果為: 3 2 1 調用C的構造函數,則B,A構造函數都將使用傳入的參數進行初始化。

我們再看使用虛基類的情況:

<code>class A
{
private:
int a;
public:
A(int n=0):a(n){}
int get(){return a;}
};
class B:virtual public A
{
private:
int b;
public:
B(int m=0,int n=0):A(n),b(m){}
int get(){return b;}
};
class C:public B
{
private:
int c;
public:
C(int q=0,int m=0,int n=0):B(m,n),c(q){}
int get(){return c;}
void Show()
{
std::cout<
<:get> }
};
int main()
{
C c(1,2,3);
c.Show();
return 0;
}/<code>

輸出結果為: 0 2 1 說明A並沒有使用傳入的參數進行初始化, 這是因為在虛基類中,我們假想會有多個子類向虛基類傳遞參數,為了避免這種情況, 在虛基類的情況下,禁止了子類C使用中間類B向虛基類A傳遞參數,此時調用的是A的默認構造函數。 那麼我們該如何使用參數,初始化虛基類呢? 答案是我們可以在子類C中,直接調用虛基類A的構造函數進行初始化,如以下代碼所示:

<code>class A
{
private:
int a;
public:
A(int n=0):a(n){}
int get(){return a;}
};
class B:virtual public A
{
private:
int b;
public:
B(int m=0,int n=0):A(n),b(m){}
int get(){return b;}
};
class C:public B
{
private:
int c;
public:
C(int q=0,int m=0,int n=0):A(m),B(m,n),c(q){}

int get(){return c;}
void Show()
{
std::cout<<:get> }
};
int main()
{
C c(1,2,3);
c.Show();
return 0;
}/<code>

輸出結果為: 3 2 1

跳過中間類,直接調用基類的構造函數,這種方式只適合虛基類。 在非虛基類中會報錯“不允許使用間接非虛擬基類”。

參考資料:《C++ Primer.Plus》 pp.551-567


一個類可以同時繼承多個類,稱為多繼承。下列關於多個繼承和虛基類的表述中,錯誤的是

A.每個派生類的構造函數都要為虛基類構造函數提供實參 B.多繼承時有可能出現對基類成員訪問的二義性問題 C.使用虛基類可以解決二義性問題並實現運行時的多態性 D.建立最派生類對象時,虛基類的構造函數會首先被調用

正確答案 C 答案解析: [解析] 本題考核虛基類。C++中,通過虛擬基類所派生的類,在所產生的對象中,只包含了一個和其他類共享的基礎對象,也就是說,從同一個基類中以虛擬方式派生的所有類,在它們所產生的對象裡,不會有一份基礎對象,而只是在內存裡保留一份基礎對象,而派生類中只保留指向此基礎對象的指針,這樣就不會同時有兩份基類對象的情形發生。用虛基類可以解決二義性問題。但是實現運行時的多態性是虛函數。


C++學習大綱:多繼承

通過分享實用的計算機編程語言乾貨,推動中國編程到2025年基本實現普及化,使編程變得全民皆知,最終實現中國編程之崛起,這裡是中國編程2025,感謝大家的支持。

原文鏈接:https://blog.csdn.net/haitaolang/article/details/70847419


分享到:


相關文章: