C 中的繼承(二)

2021-07-16 12:55:30 字數 3462 閱讀 1132



一、基本概念

1、類的繼承,是新的類從已有類那裡得到已有的特性。或從已有類產生新類的過程就是類的派生。原有的類稱為基類或父類,產生的新類稱為派生類或子類。

2、派生類的宣告:

class 派生類名:繼承方式 基類名1, 繼承方式 基類名2,...,繼承方式 基類名n ;

3、乙個派生類可以同時有多個基類,這種情況稱為多重繼承,派生類只有乙個基類,稱為單繼承。直接派生,間接派生。

4、繼承方式規定了如何訪問基類繼承的成員。繼承方式有public, private, protected。如果不顯示給出繼承方式,預設為private繼承。繼承方式指定了派生類成員以及類外物件對於從基類繼承來的成員的訪問許可權。

5、派生類繼承基類中除構造和析構函式以外的所有成員。

6、派生類生成:

吸收基類成員(除構造析構函式以外的所有成員);

改造基類成員(根據繼承方式調整基類成員的訪問,函式在子類中的覆蓋,以及虛函式在子類中的覆蓋);

新增新的成員;

7、公有繼承

當類的繼承方式為公有繼承時,基類的公有和保護成員的訪問屬性在派生類中不變,而基類的私有成員不可訪問。即基類的公有成員和保護成員被繼承到派生類中仍作為派生類的公有成員和保護成員。派生類的其他成員可以直接訪問它們。無論派生類的成員還是派生類的物件都無法訪問基類的私有成員。

8、私有繼承

當類的繼承方式為私有繼承時,基類中的公有成員和保護成員都以私有成員身份出現在派生類中,而基類的私有成員在派生類中不可訪問。基類的公有成員和保護成員被繼承後作為派生類的私有成員,派生類的其他成員可以直接訪問它們,但是在類外部通過派生類的物件無法訪問。無論是派生類的成員還是通過派生類的物件,都無法訪問從基類繼承的私有成員。通過多次私有繼承後,對於基類的成員都會成為不可訪問。因此私有繼承比較少用。

9、保護繼承

保護繼承中,基類的公有成員和私有成員都以保護成員的身份出現在派生類中,而基類的私有成員不可訪問。派生類的其他成員可以直接訪問從基類繼承來的公有和保護成員,但是類外部通過派生類的物件無法訪問它們,無論派生類的成員還是派生類的物件,都無法訪問基類的私有成員。

二、派生類的建構函式和析構函式

1、派生類中由基類繼承而來的成員的初始化工作還是由基類的建構函式完成,然後派生類中新增的成員在派生類的建構函式中初始化。

2、派生類建構函式的語法:

派生類名::派生類名(引數總表):基類名1(參數列1),基類名(引數名2)....基類名n(引數名n),內嵌子物件1(參數列1),內嵌子物件2(參數列2)....內嵌子物件n(參數列n)

注:建構函式的初始化順序並不以上面的順序進行,而是根據宣告的順序初始化。

3、如果基類中沒有不帶引數的建構函式,那麼在派生類的建構函式中必須呼叫基類建構函式,以初始化基類成員。

4、派生類建構函式執行的次序:

呼叫基類建構函式,呼叫順序按照它們被繼承時宣告的順序(從左到右);

呼叫內嵌成員物件的建構函式,呼叫順序按照它們在類中宣告的順序;

派生類的建構函式體中的內容

#include #include using namespace std;

class b1

};class b1:publicb0;

class b2:publicb0;

class d1:public b1, public

b2};

intmain()

輸出結果為:

member of b0 2

member of b0 3

在這種情況下,派生類物件在記憶體中就同時擁有成員nv及fun的兩份拷貝。但是很多情況下,我們只需要這樣乙個這樣的資料拷貝,同一成員的多份拷貝增加了記憶體的開銷。可以通過虛函式來解決這個問題。

4、虛基類

為了解決前面提到的多重拷貝的問題,可以將共同基類設定為虛基類,這時從不同的路徑繼承過來的同名資料成員在記憶體中就只有乙個拷貝,同乙個函式也只有乙個對映。

虛基類的宣告是在派生類的宣告過程,其語法形式為:

class 派生類名::virtual 繼承方式 基類名;

例子:

#include #include 

using

namespace

std;

class

b0};

class b1:virtual

publicb0;

class b2:virtual

publicb0;

class d1:public b1, public

b2};

intmain()

輸出結果為:

member of b0 2

5、虛基類及其派生類的建構函式

一般而言,派生類只對其直接基類的建構函式傳遞引數,但是在虛基類中,不管是直接或間接虛基類的所有派生類,都必須在建構函式的成員初始化列表中列出對虛基類的初始化。

例子:

#include #include 

using

namespace

std;

class

b0

intnv;

void

fun()

};class b1:virtual

public

b0

intnv1;

};class b2:virtual

public

b0

intnv2;

};class d1:public b1, public

b2

intnvd;

void

fund()

};int

main()

以上例子看上去b0的建構函式好像被呼叫了三次,但是實際上只有d1類中的d1(int a):b0(a), b1(a), b2(a)

才是真正的呼叫了b0建構函式。

四、賦值相容規則

1、賦值相容規則是指在需要基類物件的任何地方都可以使用公有派生類的物件來替代。

2、賦值相容規則中所指的替代包括:

派生類的物件可以賦值給基類物件;

派生類的物件可以初始化基類的引用;

派生類物件的位址可以賦給指向基類的指標。

在替代之後,派生類物件就可以作為基類的物件使用,但只能使用從基類繼承的成員。

例子:

#include #include 

using

namespace

std;

class

b0};

class b1:public

b0};

class b2:public

b0};

void fun(b0 *ptr)

intmain()

輸出結果為:

b0::display()

b0::display()

b0::display()

通過這種賦值相容後,每次呼叫的同名函式都是基類的同名函式,如果想呼叫派生類的,則需要使用虛函式。

C 中的繼承(二)

前面已經總結過類中的預設的成員函式 類中的預設的成員函式 所以,既然是預設,就代表如果我們不顯示定義,編譯器就會預設生成,那麼在繼承體系中,派生類的預設成員函式又是什麼yang的呢 派生類的建構函式必須呼叫基類的建構函式初始化基類的那一部分成員。如果基類沒有預設的建構函式,則必須在派生類建構函式的初...

c 繼承 二 菱形繼承

在c 一 中,寫的程式是單繼承 即乙個子類只有乙個父類 下面將寫乙個多繼承程式 即乙個子類有兩個或兩個以上的父類 多繼承是c 的乙個缺陷 對上述 直接進行編譯會產生問題,問題在於dd.fun 編譯器報錯很明確,它不知道這裡的fun函式是要訪問b中的還是c中的。解決這個問題有兩種方案,第一種是重寫,即...

C 繼承中的二義性

當乙個類有多個基類的時候,通過所有直接基類同時進行名字查詢。多重繼承的派生類有可能從兩個或多個基類繼承同名成員,對該成員如果不加限定的話,這樣使用就是二義性的。即使兩個繼承的函式有不同的形參表也會產生錯誤,類似的,即使函式在乙個類中是私有的而在另乙個類中是公用的或受保護的,也同樣是錯誤的。名字查詢總...