函數重載(overload)和函數重寫(override)

1. 前言:

  在C++中有兩個很是容易混淆的概念,分別是函數重載(overload)和函數重寫(overwirte)。雖然只相差一個字,可是它們二者之間的差異仍是很是巨大的。編程

  而經過深刻了解這兩個概念的區別,會對C++的面向對象機制有一個更深刻的理解。數組

2 函數重載(overload function)

2.1 函數重載的概念:

2.1.1 概念:

當函數具備相同的名稱,可是參數列表不相同的情形(包括參數的個數不一樣或參數的類型不一樣),這樣的同名而不一樣參數的函數之間,互相被稱之爲重載函數。ide

2.1.2 基本條件:

  • 函數名必須相同;
  • 函數參數必須不相同,能夠是參數類型或者參數個數不一樣;
  • 函數返回值能夠相同,也能夠不相同。(備註:可是若是函數的名稱和參數徹底相同,僅僅是返回值類型不一樣,是沒法進行函數重載的。

2.1.3 注意:

  • 只能經過不一樣的參數樣式進行重載,例如:不一樣的參數類型,不一樣的參數個數,或者不一樣的參數順序
  • 不能經過訪問權限、返回類型、拋出的異常不一樣而進行重載;
  • 重載的函數應該在相同的做用域下。

2.1.4 函數重載實例判斷:

如下的集中寫法,分別表示了哪些是重載的,哪些不是重載的。 
(1) void func1( int arg1); 
(2) void func1( double arg1); 
(3) void func1( int arg1, int arg2); 
(4) bool func1(int arg1, double arg2) 
(5) int func1(int arg1);函數

在上述的5個函數中,函數名稱都是func1,徹底相同;可是: 
(2)與(1)的參數個數相同,參數類型不一樣,構成重載; 
(3)與(1)和(2)的參數個數不一樣,構成重載; 
(4)與(1)和(2)的參數個數不一樣,與(3)的參數個數相同,可是第二個參數類型不一樣,構成重載; 
(5)與(1)的參數個數和參數類型均相同,僅返回值的類型不相同,不構成重載;可是(5)與(2),(3)和(4)除返回值不一樣外,均有參數類型或參數個數不一樣的狀況,所以構成重載關係。spa

 

2.2 函數重載的應用

讀者可能會問,既然函數重載這個概念這麼拗口,並且有時候又容易和函數重寫概念弄混而致使出錯,那麼爲何在C++裏面要有這麼一個概念出現呢?指針

緣由其實也很簡單,就是由於在一個程序中,會出現不少不少,完成的函數功能徹底相同,而僅僅是函數的參數略有不一樣的情形。這時若是沒有函數重載這個概念,那麼開發人員恐怕就要爲如何爲功能徹底相同的函數起不一樣的名而頭疼了。調試

 

在各類開源的庫中,咱們也常常能夠看到函數重載的身影。好比:對象

(1)類的構造函數,一般就是函數重載的典型應用。由於一個類一般是能夠有不少種構造方式的。 
如QT裏面的QString類的構造函數,提供了9種不一樣的構造函數,這9種構造函數的函數名徹底相同,可是它們的參數類型或參數個數卻不徹底相同,所以是合法的。如圖所示: blog

(2)類的成員函數,如賦值函數等。 
如VTK的vtkImageData類的兩個成員函數就是重載的。如: 繼承

 

 

這兩個成員函數的函數名稱都是SetDimensions(),可是第一個函數的參數是3個int型的值;另外一個函數的參數是一個const int型的數組,返回值都是void。這樣也是能夠構成函數重載的。

在安裝有編程助手的狀況下編寫代碼時,若是遇到一個類的成員函數有重載時,助手一般會提示開發者,要選擇哪個重載函數。以下圖所示。vtkImageData的SetDimensions()函數有兩個重載形式,所以在編寫代碼時,助手會提示2 of 2,表示這是2個重載函數中的第二個,點擊能夠切換到第一個重載函數。開發者須要根據上下文的要求,來選擇相應的重載函數進行編寫。

 


 

 

3 函數重寫(override function)

雖然與函數重載僅僅只有一個字的差異,可是這兩個概念倒是相差了很遠很遠。它倆彷佛一點關係都沒有。也正由於如此,這個很是考驗C++語言的基本功,也是歷年C++筆試中常常會出現的考題。

3.1 函數重寫(override function)

3.1.1 概念:

函數重寫,也被稱爲覆蓋,是指類從新定義父類中有相同名稱和參數的虛函數,主要在繼承關係中出現

3.1.2 基本條件:

  • 重寫的函數和被重寫的函數必須都爲virtual函數,並分別位於基類和派生類中;
  • 重寫的函數和被重寫的函數,函數名和函數參數必須徹底一致
  • 重寫的函數和被重寫的函數,返回值相同,或者返回指針或引用,而且派生類虛函數返回的指針或引用的類型基類中被替換的虛函數返回的指針或引用的類型或者其子類型(派生類型)。

3.2 函數重寫的應用

有個規則是賦值兼容性原則,而這個規則有bug,當子類和父類的函數重名的時候,不論是基類的對象去指向/引用子類對象,都是調用基類的函數,而和子類無關,這明顯是一個bug,

因此,只能用函數重寫(也就是引出了多態),這樣就能夠區分和調用子類和父類裏重名的函數了。[這裏不能用函數重載是由於這裏發生在兩個類裏,而重載不只僅是在一個類裏進行區分]

 PS: 重寫/多態是類的特性,而重載不是,在全局函數裏也能夠用重載
 

今天在工做的時候,就是由於在重寫基類的某一個虛函數時,因爲在複製時把函數的參數類型和基類的參數類型搞得不一致了,致使重寫失敗。

所以,在調試代碼時,本覺得程序會進入派生類的重寫後的函數中,可是實際卻一直進入基類的函數中。最後在網上查詢緣由時,才恍然大悟,原來是因爲本身的失誤,而致使了重寫失敗。

具體是: 
Dx3DActorRotationPanOplayer : public DxBaseOplayer. 
在基類DxBaseOplayer中有一系列的關於響應鼠標事件的虛函數: 

 

其中,在派生類中我想從新實現其中的一個虛函數 OnMouseLeave()。 
可是,我在子類定義該函數時,卻寫成了: 

 

表面上看起來彷佛很像。可是仔細一看,函數的參數是不相同的。 

基類的第一個參數類型是:QEvent, 而派生類的第一個參數類型是:QMouseEvent。

正是因爲這個參數類型的不一樣,而致使了派生類實際並無重寫基類的這個成員函數

 

所以,在基類的指針調用這個函數時,便沒法調用到子類的這個重寫函數了。 只要把派生類的第一個參數類型也修改成QEvent,那麼便實現了函數的重寫了。

相關文章
相關標籤/搜索