C 學習筆記(2) 繼承與派生

2021-10-08 07:14:37 字數 4287 閱讀 3221

開始之前,我們先說一句,我們打算用三篇筆記搞定c++物件導向基礎,後面開始就要寫泛型程式設計和stl了。節奏有點快是不是?

從乙個類派生出另乙個類的格式如下:

class

a//基類

;classb:

public a//派生類,繼承方式一般用public,當然也有其他方式

;

此時類a公有派生出了類b,類a稱為基類,類b稱為派生類,派生類物件也是基類物件。

公有派生的情況下,存在著三條賦值相容規則(這個和c++三種傳遞方式(值傳遞、指標傳遞和引用傳遞)相對應):

注意,這三條規則僅限於公有派生,如果是私有派生和保護派生則不成立。

這個規則很好理解。基類沒有派生類的全部成員,但派生類有基類的全部成員,因此派生類》基類,基類物件當然可以接收派生類的值、址和引用了,但是反過來卻不行。

下面這個例子(續上面的程式)展示了這三條規則:

a a;

b b;

a = b;

//派生類物件賦值給基類物件

a &r = b;

//派生類物件初始化基類引用

a *pa =

&b;//派生類物件的位址賦值給基類的指標

b *pb =

&b; pa = pb;

//派生類的指標賦值給基類的指標

如果這三條反過來是不成立的。一般來講,基類的指標不能賦值給派生類的指標。但是通過強制型別轉換,也可以將基類指標強制轉換成派生類指標,然後再賦值給派生類指標。只是這樣做是有風險的。比如下面這個例子(續上面的程式):

a *pa =

&b;//基類指標能指向派生類物件

b *pb =

&a;//出錯,派生類指標不能指向基類物件

b *pb =

(b*)

&a;//強制轉換型別,慎用

pa -

> n1 =1;

pa -

> n2 =2;

//出錯,pa是基類指標,編譯器只會去找基類的成員,不會去找派生類的成員

pb -

> n1 =3;

//能編譯成功,但執行時可能會出現意外的結果

另外,還有多層次的派生。下面這個例子展示了多重派生:

class

a//基類

;classb:

public a//派生類

;classc:

public b//派生類

;

在本例中,類a派生類b,類b派生類c;類a是類b的直接基類,類b是類c的直接基類;類a是類c的間接基類

派生類和基類可能有同名成員變數同名成員函式(或二者兼有),這種現象叫做覆蓋。看看下面我的程式是如何解決這個問題的:

#include

using

namespace std;

class

a//基類 };

classb:

public a //派生類

void

func()

;};void b::

func()

intmain()

程式輸出結果:

1

2classb!

class

a!

對於多重派生來說也是一樣的,對於重名的成員變數或成員函式,你不寫類名::,那麼系統預設是屬於本類的。為防止困惑,遇到重名的還是最好都寫上類名::吧。

訪問範圍說明符protected,是用來修飾成員變數或成員函式的。protected一般用來修飾基類的成員變數或成員函式,這樣派生類也可以去訪問基類的成員變數或成員函式了,但是在類定義外部是訪問不了的(三種範圍說明符的關係如下圖,可能不太嚴謹)。

因此,保護成員的可被訪問範圍(自己的和我派生的,都能訪問,其他類不能訪問)大於私有成員(只能自己類內部訪問,派生的也不行),而小於公有成員(誰都能訪問)。

舉乙個下面程式的例子:

#include

using

namespace std;

classa;

classb:

public a};

intmain()

注意,在基類中,一般都將需要隱藏的成員說明為保護成員而非私有成員。派生類物件建立時,也是要呼叫建構函式進行初始化的,這個過程跟封閉類物件比較類似,但又不盡相同。在派生類內部定義建構函式的格式如下:

建構函式名(形參表)

:基類名(基類建構函式實參表)

建構函式和析構函式在基類物件和派生類物件裡有不同的生存期,下面我們用乙個程式來說明它們是怎麼運作的:

#include

using

namespace std;

classa~

a()void

print()

};classb:

public a~b

()void

print()

};intmain()

輸出結果如下:

a被建造!

b被建造!3,

41,2

b被拆毀!

a被拆毀!

由輸出結果可以看到,在派生類物件構建時,先執行基類的建構函式,再執行派生類的建構函式;在派生類物件消亡時恰好相反,先執行派生類的析構函式,再執行基類的析構函式。這個步驟與封閉類物件的建立和消亡恰好相反。

對於多層次的派生結構來說,派生類物件生成時,會從最頂層的基類開始逐層往下執行所有基類的建構函式,最後再執行自身的建構函式;當派生類物件消亡時,會先執行自身的析構函式,然後從底向上依次執行各個基類的析構函式。

假如在上面程式main函式裡加上a a(5, 6);,那麼出現的情況是:整個程式a被建造了兩次(這個正常),a被銷毀了兩次,而不是一次。如果是多層次派生結構,又定義了許多物件,那麼中間的構造和析構函式就會被呼叫很多次了。

上面四節說的都是公有派生的大前提下實現的,因為公有派生是最常用的。實際上還有私有派生和保護派生,這兩個反而不常用。下表說明了不同派生方式導致派生類的可訪問範圍的不同

基類成員

公有派生

私有派生

保護派生

私有成員

不可訪問

不可訪問

不可訪問

保護成員

保護私有

保護公有成員

公有私有

保護下面我們用程式來說明私有派生的訪問範圍(一看就懂):

#include

using

namespace std;

classa;

classb:

private a};

classc:

public b};

intmain()

下面我們用程式來說明保護派生的訪問範圍(一看就懂):

#include

using

namespace std;

classa;

classb:

protected a};

classc:

public b};

intmain()

無論是什麼派生方式,私有成員都只允許自己訪問,其他類是不可訪問的。公有派生的特點是,基類該是什麼成員,派生類也該是什麼成員,原有訪問範圍不變。保護派生的特點是,無論基類是什麼成員(除了私有成員),到了派生類就都是保護成員。私有派生的特點是,無論基類是什麼成員(除了私有成員),到了派生類就都是私有成員。

一般情況下,都應該使用公有派生。

暫時先寫到這吧,往後修改可能會有補充。

C 繼承與派生 學習筆記

一 繼承和派生的基本概念 繼承是c 語言中的一種重要的機制,也是物件導向的乙個重要特徵,實現了物件導向程式設計思想中軟體復用的功能。繼承的實質就是通過現有的類的特徵,構造乙個具有現有類特徵的新類,這個新類成為派生類。派生類是從乙個或者多個以前定義的類 基類 繼承資料和函式,同時增加或者重定義資料和函...

C 繼承與派生 學習筆記

一 繼承和派生的基本概念 繼承是c 語言中的一種重要的機制,也是物件導向的乙個重要特徵,實現了物件導向程式設計思想中軟體復用的功能。繼承的實質就是通過現有的類的特徵,構造乙個具有現有類特徵的新類,這個新類成為派生類。派生類是從乙個或者多個以前定義的類 基類 繼承資料和函式,同時增加或者重定義資料和函...

c 學習筆記(1)繼承與派生

1.繼承方式包括三種 public private protected。預設的繼承方式是private 例 1 公有方式繼承 class a public b 2 預設為私有繼承 class a b 2 派生類中的成員包括從基類繼承過來的成員和自己增加的成員。從基類繼承過來的成員體現了派生類從基類繼...