第八章 不要在構造和析構函式中使用虛函式

2022-03-03 22:30:56 字數 1729 閱讀 4537

本文將講解乙個新手c++程式設計師經常會犯的錯誤 - 在構造/析構函式中使用虛函式,並分析錯誤原因所在以及規避方法。

首先,假設我們以乙個實現交易的類為父類,然後乙個實現買的類,乙個實現賣的類為其子類。

這三個類的物件初始化過程中,都需要完成註冊的這麼一件事情 (函式)。然而,各自註冊的具體行為是不同的。

有些人會寫出以下這樣的**:

1

class

transaction ;

1011

transaction::transaction()

1617

class buytransaction : public

transaction ;

2324

class selltransaction : public

transaction ;

在這段**中,編寫者認為,子類會繼承父類的建構函式,而繼承之後,不同的子類又會呼叫他們自己的實現的註冊函式。

這是錯誤的。

因為在子類呼叫父類的建構函式期間,子類型別是其父類型別,這個時候執行父類的建構函式其內部呼叫的註冊函式也是父類版本的,而非子類版本的。

由於上面所說的錯誤,一些人想到了虛函式解決方案:

1

class

transaction ;

1011

transaction::transaction()

1617

class buytransaction : public

transaction ;

2324

class selltransaction : public

transaction ;

很遺憾,這麼做還是行不通。一旦你構造乙個子類物件,鏈結器會提示你鏈結失敗 - 呼叫未定義的純虛函式。這說明子類建構函式使用的註冊函式依然是父類的。

很多人開始吐槽c++(第一次碰到這種情況的時候我也是),覺得這樣的設定很奇葩。

但其實c++這麼設定是有原因的:在父類建構函式執行期間,子類的成員變數並沒有初始化完全,因此在此階段呼叫子類的成員函式應當被禁止。

首先,至此我們要明確:不能在建構函式中使用虛函式了,這麼做根本無法實現多型。

然後,採用什麼辦法能夠做到在父類建構函式中以呼叫成員函式的方式完成初始化呢?

本例中,正確的做法是在父類中將註冊函式取消其虛函式宣告,而在子類的建構函式中,自行呼叫父類建構函式並傳遞進子類物件部分相關資訊。當父類建構函式獲取到子類部分傳遞進來的資訊之後,就能根據傳遞進來的資訊,有選擇的呼叫相應註冊函式。

請看**示例:

1

class

transaction ;

1011 transaction::transaction(const std::string &loginfo)

1718

class buytransaction : public

transaction ;

2829

//子類建構函式定義

30 buytransaction :: buytransaction(/*

parameters

*/) : transaction(createlogstring(/*

parameters

*/))

31

1. 請仔細體會本文的幾個類設計過程中所體現出的物件導向思想。

2. 本文焦點是建構函式,但同樣適用於析構函式。

第八章 函式高階

在函式宣告和函式定義前加上inline 乙個簡單的計算平方的 include using namespace std inline double square double x int main 內聯函式的使用 函式經常呼叫,函式體較小,不包含迴圈之類的 引用變數的主要用途是用作函式的形參 引用變數...

總結 CLR Via C (第八章) 構造器

1 類只能擁有類自己的例項構造器 例項構造器不能被繼承 2 以下修飾符不能用於例項構造器 virtual new override sealed abstract 如果類的修飾符為abstract,那麼預設構造器可訪問性為protected,否則為public 3 如果基類沒有提供無參構造器,那麼類...

C Primer Plus 第八章 函式探幽

什麼時候建立臨時變數 如果引用引數是const,如 func const double ra 則編譯器將在下面兩種情況下生產臨時變數 1.實參的型別正確,但不是左值。如 7.0 temp 7等 2.實參的型別不正確,但可以轉換為正確的型別。如 int,long等 右值引用 c 11新增了另一種引用 ...