1. 程式人生 > >函式過載(overload)和函式重寫(override)的基本規則

函式過載(overload)和函式重寫(override)的基本規則

本文由Markdown語法編輯器編輯完成。

1. 前言:

  在C++中有兩個非常容易混淆的概念,分別是函式過載(overload)和函式重寫(overwirte)。雖然只相差一個字,但是它們兩者之間的差別還是非常巨大的。而通過深入瞭解這兩個概念的區別,會對C++的面向物件機制有一個更深入的理解。

2 函式過載(overload function)

2.1 函式過載的概念:

2.1.1 概念:

當函式具有相同的名稱,但是引數列表不相同的情形(包括引數的個數不同或引數的型別不同),這樣的同名而不同引數的函式之間,互相被稱之為過載函式。

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)除返回值不同外,均有引數型別或引數個數不同的情況,因此構成過載關係。

2.2 函式過載的應用

讀者可能會問,既然函式過載這個概念這麼拗口,而且有時候又容易和函式重寫概念弄混而導致出錯,那麼為什麼在C++裡面要有這麼一個概念出現呢?

原因其實也很簡單,就是因為在一個程式中,會出現很多很多,完成的函式功能完全相同,而僅僅是函式的引數略有不同的情形。這時如果沒有函式過載這個概念,那麼開發人員恐怕就要為如何為功能完全相同的函式起不同的名而頭疼了。

在各種開源的庫中,我們也經常可以看到函式過載的身影。比如:

(1)類的建構函式,通常就是函式過載的典型應用。因為一個類通常是可以有很多種構造方式的。
如QT裡面的QString類的建構函式,提供了9種不同的建構函式,這9種建構函式的函式名完全相同,但是它們的引數型別或引數個數卻不完全相同,因此是合法的。如圖所示:
這裡寫圖片描述

(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 函式重寫的應用

今天在工作的時候,就是因為在重寫基類的某一個虛擬函式時,由於在複製時把函式的引數型別和基類的引數型別搞得不一致了,導致重寫失敗。因此,在除錯程式碼時,本以為程式會進入派生類的重寫後的函式中,但是實際卻一直進入基類的函式中。最後在網上查詢原因時,才恍然大悟,原來是由於自己的失誤,而導致了重寫失敗。

具體是:
Dx3DActorRotationPanOplayer : public DxBaseOplayer.
在基類DxBaseOplayer中有一系列的關於響應滑鼠事件的虛擬函式:
這裡寫圖片描述

其中,在派生類中我想重新實現其中的一個虛擬函式 OnMouseLeave()。
但是,我在子類定義該函式時,卻寫成了:
這裡寫圖片描述

表面上看起來似乎很像。但是仔細一看,函式的引數是不相同的。
基類的第一個引數型別是:QEvent, 而派生類的第一個引數型別是:QMouseEvent。正是由於這個引數型別的不同,而導致了派生類實際並沒有重寫基類的這個成員函式。因此,在基類的指標呼叫這個函式時,便無法呼叫到子類的這個重寫函數了。
只要把派生類的第一個引數型別也修改為QEvent,那麼便實現了函式的重寫了。

參考連結:

未完待續……