不可不知的C++隱藏規則

     在面向對象的開發過程中,經常出現類的繼承,這裏面出現的成員函數的重載(overload)、覆蓋(override)與隱藏(hidden)很容易混淆。

首先澄清這3個概念:


重載

  1. 相同的範圍(在同一個類中)
  2. 函數名字相同
  3. 參數不同
  4. virtual 關鍵字可有可無

覆蓋(派生類函數覆蓋基類函數)

  1. 不同的範圍(分別位於派生類與基類)
  2. 函數名字相同
  3. 參數相同
  4. 基類函數必須有 virtual 關鍵字

 

隱藏(派生類的函數屏蔽了與其同名的基類函數)

  1. 如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無 virtual 關鍵字,基類的函數將被隱藏(注意別與重載混淆)
  2. 如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有 virtual關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)

下面用一個簡單的例子來闡述

 

 

    例子中,pb和pd指向同一地址,按理運行結果是相同的,但其實卻不是。由於隱藏機制的作用,部分方法的調用依賴於所使用的指針!

 

由此看來,隱藏機制似乎會帶來不少理解上的問題,但“存在即合理”:

  1. 寫語句pd->f(10)的人可能真的想調用Derived::f(char *)函數,只是他誤將參數寫錯了。有了隱藏規則,編譯器就可以明確指出錯誤,這未必不是好事。否則,編譯器會靜悄悄地將錯就錯,程序員將很難發現這個錯誤,留下禍根
  2. 假如類Derived有多個基類(多重繼承) ,有時搞不清楚哪些基類定義了函數f。如果沒有隱藏規則,那麼pd->f(10)可能會調用一個出乎意料的基類函數f,而隱藏規則的存在消滅了這個問題

 

總結

     工欲善其事,必先利其器。弄清楚這些基本概念,才能在實踐中少走彎路。

 

 2017:

時隔7年再看,當年真是才疏學淺,C++根本沒有什麼隱藏規則,使用不同類型的指針雖然指向了同一個對象,但是非虛函數並不會通過運行時虛表來綁定,反而是在編譯期靜態綁定,所以沒有什麼surprise,倒是在類繼承的設計上,確實埋了個坑,不過一般這種通過基類訪問不同子類實例的場景,對於public方法,應該都定義成virtual的以便擴展

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章