HOWTO · C++
C++ 中的函式過載 VS 覆蓋
本文演示如何在 C++ 中使用函式過載 VS 覆蓋
本頁內容
函式多載與函式覆寫在 C++ 中解決的是不同問題。函式多載是在同一個作用域中,讓多個函式使用相同名稱但採用不同的參數列表;編譯器會根據呼叫時提供的引數選出符合的函式。函式覆寫則是讓衍生類別以相符的實作取代繼承而來的 virtual 函式;透過基底類別參考或指標呼叫時,執行階段會將呼叫分派給衍生類別物件。
在 C++ 中,函式多載與函式覆寫的意義
函式多載是從參數不同的函式中選出要呼叫的版本;函式覆寫則是在繼承階層中替換行為。單靠函式的回傳型別無法區分多載,而函式覆寫要求基底類別中的函式是 virtual。在衍生類別的宣告中加上 override,可讓編譯器檢查它是否確實符合基底類別的虛擬函式。
函式多載的運作方式
在同一個作用域中宣告多個同名函式,並為它們指定不同的參數列表。參數列表可以有不同數量的參數,或採用不同型別。呼叫函式時,多載解析會根據引數及候選函式的參數型別來選擇版本。回傳型別不會用來選擇多載,因此兩個宣告若只有回傳型別不同,就不能構成有效的多載集合。
執行這個範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
#include <iostream>
class Formatter {
public:
void show(int value) const {
std::cout << "integer: " << value << '\n';
}
void show(double value) const {
std::cout << "decimal: " << value << '\n';
}
};
int main() {
Formatter formatter;
formatter.show(7);
formatter.show(2.5);
}
integer: 7
decimal: 2.5
提供的執行證據確認這個範例已成功執行,且輸出如所示。整數與小數引數會選到不同的 show 多載。新增多載時,請確認參數列表有實質差異,並確保呼叫不會產生歧義。
函式覆寫的運作方式
基底類別將函式宣告為 virtual;衍生類別則提供名稱、參數列表、相容限定詞與回傳型別相符的函式。請在衍生類別的宣告中標記 override,如此一來,若有不相符之處,編譯器就會在編譯時提出診斷。透過基底類別參考或指標呼叫函式時,虛擬派發會依物件選出最終覆寫函式。
執行這個範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
#include <iostream>
class Message {
public:
virtual void print() const {
std::cout << "message\n";
}
};
class Alert : public Message {
public:
void print() const override {
std::cout << "alert\n";
}
};
int main() {
Alert alert;
const Message& message = alert;
message.print();
}
alert
提供的執行證據確認這個範例已成功執行,且輸出如所示。message 的型別雖然是基底類別,但它參照的是 Alert,因此虛擬呼叫會使用 Alert::print。基底類別也可以將函式宣告為純虛擬函式,寫成 = 0;這樣的類別是抽象類別,必須由具體衍生類別實作其純虛擬函式後,才能建立物件。
函式多載與函式覆寫:主要差異
| 面向 | 函式多載 | 函式覆寫 |
|---|---|---|
| 目的 | 為不同引數提供同名操作 | 針對衍生型別特化繼承而來的行為 |
| 條件 | 同一作用域中有不同的參數列表 | 存在繼承關係,且基底類別有相符的 virtual 函式 |
| 選擇方式 | 編譯時根據呼叫引數進行多載解析 | 執行時透過基底類別參考或指標進行虛擬派發 |
| 實用檢查 | 確認呼叫會選到預期的多載 | 加上 override,確認宣告確實相符 |
多載不需要繼承或虛擬函式也能成立。覆寫則仰賴繼承與虛擬派發;它不會因為傳入不同的引數列表而被選中。
常見錯誤與辨識方式
衍生類別中有同名函式,不代表它一定覆寫了基底類別的函式。如果基底函式不是 virtual,衍生類別的宣告會隱藏基底類別中的同名函式,而不會啟用虛擬派發。如果參數、const 限定詞或函式型別的其他部分不相符,預期的覆寫就可能失敗;加上 override 可以在編譯時揭露這類不相符之處。
不要只靠更改回傳型別來建立多載。另外,若需要多型行為,避免以值傳遞衍生物件:將衍生物件複製到基底類別物件時,會發生物件切片,衍生部分會被移除。請使用基底類別參考或指標,以保留動態派發。一般情況下,優先使用自動物件或智慧指標管理所有權;若透過基底類別指標刪除衍生物件,基底類別應有虛擬解構函式。