essential c 讀書筆記5

2021-10-04 12:33:34 字數 4160 閱讀 5232

繼承:將一群相關的類組織起來,並讓我們得以分享期間的共通資料和操作行為; 父類:基類; 子類:派生類。

多型:可以使我們操縱不同類時,如同操縱單一個體。 讓基類的pointer 和 reference 得以十分透明的指向任何乙個派生類的物件。

動態繫結:解析操作會延遲到執行時才進行。

靜態繫結:程式執行之前就已經解析出應該呼叫哪乙個函式。

虛函式:virtual 實現了多型的機制。基類定義虛函式,子類可以重寫該函式;在派生類中對基類定義的虛函式進行重寫時,需要在派生類中宣告該方法為虛方法。

當子類重新定義了父類的虛函式後,當父類的指標指向子類物件的位址時,[即b b; a a = &b;] 父類指標根據賦給它的不同子類指標,動態的呼叫子類的該函式,而不是父類的函式,

且這樣的函式呼叫發生在執行階段,而不是發生在編譯階段,稱為動態聯編。而函式的過載可以認為是多型,只不過是靜態的。

同時在函式構造時,會依次呼叫父類、子類、子子類的呼叫函式;析構的順序則相反。 使用虛函式後,子類實現父類的虛函式後,呼叫該函式就會呼叫子類的函式而不是父類的函式

所有數列型別名稱被放在乙個名為ns_type的列舉型別中

class

num_sequence

;}

nstype() 函式會檢測整數引數是否返回某一有效數列。

class

num_sequence

};

static_cat是個特殊轉換記號,可將num轉換為對應的ns_type

不帶繼承的多型的缺點:費工夫,且事後維護工程浩大

定義抽象類的第乙個步驟:找出所有子類共通操作行為。就是定義基類的公有介面。

class

num_sequence

class

num_sequence

第三步:找出每個操作行為的訪問層次。皆可訪問:public 除基類外不需要用到:private 可以被派生類用到,但不允許一般程式使用

class

num_sequence

;virtual

intelem

(int pos)

const=0

;virtual

const

char

*what_am_i()

const=0

;//不確定是否有關 與型別

virtual ostream&

print

(ostream &os = cout) count =0;

static

intmax_elems()

;protected

:virtual

void

gen_elems

(int pos)

const=0

;bool

check_integrity

(int pos)

;//檢測是否有效

const

static

int _max_elems =

1024

;}

每個虛函式,要麼得有定義,要麼設定為純虛函式。

任何類如果宣告乙個或多個純虛函式,那麼由於其介面的不完整性(純虛函式沒有函式定義),程式無法為其產生任何物件。這種類只能作為派生類的子物件使用,而且前提是這些派生類必須

為所有虛函式提供確切的定義。

為什麼要定義純虛函式?

純虛函式是為你的程式制定一種標準,即只要你繼承了我,就必須按照我的標準來,實現我所有的方法,否則你也是虛擬的。

根據規則,凡基類定義有乙個或讀多個虛函式,應該要將其destructor宣告為virtual。

class

num_sequence

;

派生類由兩部分組成:一是基類構成的子物件,由基類的non-static data member組成;二是派生類的部分。

派生類的名稱之後緊跟著冒號,關鍵字public,及基類的名稱。

#include

"num_sequence.h"

class

fibonacci

:public num_sequence

fibonacci必須為從基類繼承而來的每個純虛函式提供對應的實現,還必須宣告專屬的member。

派生類的虛函式必須精確吻合基類中的函式原型,在類之外對虛函式進行定義時,不必指明關鍵字virtual。

每當派生類有某個member與其基類的member同名,便會遮掩注基類的那份member。也就是說,派生類內對該名稱的任何使用,都會被解析為該派生類自身的那份member,而非繼承來的那份member。

該問題的產生是由於基類中該函式 被視為虛函式。

data member如果是個reference,必須在constructor的member initialize list中加以初始化。一旦初始化,就再也無法指向另乙個物件。如果data member是pointer,就可以在construction內加以初始化,

也可以將它初始化為null,稍後再令它指向某個有效的記憶體位址。

初始化操作可以留給每個派生類,但這麼做會有潛在的危機。

較好的設計方式是,為基類提供constructor,並利用這個constructor處理基類所宣告的所有data member的初始化操作。

如果我們繼承了純虛函式,那麼這個派生類也會被視為抽象類,也就無法為它定義任何物件。

為什麼要定義純虛函式?

純虛函式是為你的程式制定一種標準,即只要你繼承了我,就必須按照我的標準來,實現我所有的方法,否則你也是虛擬的。

如果我們決定覆蓋基類所提供的虛函式,那麼派生類提供的新定義,其函式原型必須完全符合基類所宣告的函式原型,包括:引數列表、返回型別、常量性(const-ness)。

「返回型別必須完全吻合」規則也有意外 – 當基類的虛函式返回某個基類形式時,

class

num_sequence

派生類中的同名函式便可以返回該基類所派生出來的型別

class

fibonacci

:public num_sequence

}

怎麼合理設計乙份 what_am_i()函式,使其實現其功能?

1、在每個子類都擁有乙份what_am_i()函式,都返回乙個足以代表該類的字串;

2、只在父類提供乙份what_am_i()函式,令各派生類通過繼承機制加以復用。

3、為num_sequence增加乙個string member,並令每乙個派生類的constructor都將自己的類名作為引數,傳給num_sequence的constructor。

4、利用typeid運算子。執行時型別鑑定機制的一部分,由程式語言支援。

#include

inline

const

char

* num_sequence::

what_am_i()

const

ps -

>

gen_elems(64

);

預期呼叫的是fibonacci的gen_elems。但編譯時卻會發生錯誤。

為了呼叫fibonacci所定義的gen_elems(),必須指示編譯器,將ps的型別轉換為fibonacci指標。static_cast 運算子可以擔起這項任務。

if

(typeid

(*ps)

==typeid

(fibonacci)

)

static_cast 也有潛在危險,因為編譯器無法確認我們所進行的轉換操作是否完全正確。

dynamic_cast 運算子就可以提供有條件的轉換:

if

(fibonacci *pf =

dynamic_cast

>

(ps)

) pf-

>gen_e;

ems(64)

;

重讀Essential C 讀書筆記2

重讀essential c 讀書筆記2 by sssa2000 7 25 2004 第二章 面向過程的程式設計風格 很久以前我也很困惑為什麼要有面向過程物件導向的程式設計風格,雖然現在已經有很深的體會。其實不管是什麼風格,只要能更好地解決問題就是好的風格。1 傳值和傳址 lippman 在說明這個問...

讀書筆記 5

解碼gdi物件控制代碼 今天都是在探索gdi內部的結構,在微軟的文件中並沒有系統的記載,雖然我覺得很有道理,但到底是不是這樣只有微軟自己知道了 1 先看一下gdi控制代碼的定義,如hpen是這樣定義的 如果strict已經被定義了 struct hpen typedef struct hpen hp...

Effective C 讀書筆記 5

條款5 了解c 默默編寫並呼叫哪些函式 預設的函式包括 建構函式 copy建構函式 copy賦值運算子和析構函式,所有這些函式都是public且inline。這些函式僅當被呼叫的時候才會被編譯器建立出來。除非這個class的base class自身宣告有virtual析構函式,則這個class的析構...