開始之前,我們先說一句,我們打算用三篇筆記搞定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 派生類中的成員包括從基類繼承過來的成員和自己增加的成員。從基類繼承過來的成員體現了派生類從基類繼...