函數重載講解

雖然在初識C++-CSDN博客中介紹過,但還是感覺要單發出來大概講解下

什么是函數重載?

函數重載是指在同一個作用域內,函數名相同,但它們的 參數列表 不同。C++ 允許你根據函數的參數個數、類型或者順序的不同來定義多個同名函數。編譯器會根據函數調用時提供的參數自動選擇最合適的函數版本。

為什么需要函數重載?

函數重載的主要目的是為了讓代碼更加 簡潔可讀。你可能會有不同的需求,在這些需求下你需要執行類似的操作(例如打印、加法、計算等)。通過函數重載,你不需要為每個需求創建一個新的函數名,而是通過相同的函數名來處理不同的情況。

函數重載的規則

  1. 函數名必須相同:這是函數重載的基礎,必須要有相同的函數名。
  2. 參數列表必須不同:這可以是參數的個數、類型或者順序不同。返回類型不參與重載的判斷。
  3. 返回類型不影響重載:不能僅通過返回類型來區分重載函數。

?舉點例子

1.?假設我們有一個 print 函數,目的是輸出信息。根據不同的信息,我們可能傳入不同數量的參數。例如,打印一個整數,或者打印一個整數和一個字符串:

#include <iostream>
using namespace std;void print(int a) {cout << "Integer: " << a << endl;
}void print(int a, string b) {cout << "Integer: " << a << " and String: " << b << endl;
}int main() {print(5);             // 調用 print(int)print(10, "Hello");   // 調用 print(int, string)return 0;
}

測試結果?

  • 第一個 print(5) 調用了只有一個參數的 print(int a) 版本。
  • 第二個 print(10, "Hello") 調用了接收 intstring 兩個參數的 print(int a, string b) 版本。

?這說明

?編譯器根據傳入的參數數量來選擇合適的函數版本。

2.?如果想根據不同的數據類型來輸出不同的信息,可以通過類型來重載函數。比如,print 函數可以根據參數類型不同,打印整數、浮點數或者字符串:

#include <iostream>
using namespace std;void print(int a) {cout << "Integer: " << a << endl;
}void print(double a) {cout << "Double: " << a << endl;
}void print(string a) {cout << "String: " << a << endl;
}int main() {print(10);          // 調用 print(int)print(3.14);        // 調用 print(double)print("Hello");     // 調用 print(string)return 0;
}

?測試結果

  • print(10) 調用了 print(int a),因為 10 是整數。
  • print(3.14) 調用了 print(double a),因為 3.14 是浮動數。
  • print("Hello") 調用了 print(string a),因為 "Hello" 是字符串。

結論

?編譯器會根據傳入參數的數據類型來選擇合適的重載函數。

3.?如果函數的參數順序不同,也可以進行重載。例如,假設你有兩個函數,分別接受兩個參數 intdouble,但它們的順序不同:

#include <iostream>
using namespace std;void print(int a, double b) {cout << "Int and Double: " << a << ", " << b << endl;
}void print(double a, int b) {cout << "Double and Int: " << a << ", " << b << endl;
}int main() {print(10, 3.14);    // 調用 print(int, double)print(3.14, 10);    // 調用 print(double, int)return 0;
}

測試結果

  • print(10, 3.14) 調用了 print(int a, double b),因為第一個參數是整數,第二個是浮動數。
  • print(3.14, 10) 調用了 print(double a, int b),因為第一個參數是浮動數,第二個是整數。

結論

編譯器根據參數的順序來判斷調用哪個函數版本。?

重載函數的限制

  1. 返回類型不參與重載判斷 你不能僅僅通過改變返回類型來進行函數重載。例如,下面的代碼是錯誤的:

    int add(int a, int b) { return a + b; }
    double add(int a, int b) { return a + b; }  // 錯誤:僅通過返回類型不能區分
    

    這會導致編譯錯誤,因為編譯器無法通過僅返回類型的不同來決定到底應該調用哪個函數版本。

  2. 重載的歧義問題 如果傳入的參數能夠匹配多個重載版本,編譯器會發生歧義錯誤。例如,以下代碼就會出錯:

    void print(int a) { cout << "Integer: " << a << endl; }
    void print(double a) { cout << "Double: " << a << endl; }print(10);   // 明確調用 print(int)
    print(10.5); // 明確調用 print(double)
    print(10.0); // 可能有歧義,編譯器無法確定是否調用 int 或 double
    

介紹完了基礎,進入拓展環節??

重載函數的匹配規則

通過上面三個例子我們了解了C++ 編譯器選擇合適的重載函數時,會根據參數的類型、個數以及順序來匹配。但匹配的規則可不止這點。

1. 精確匹配

當一個重載函數的參數類型完全匹配時,編譯器會選擇它。例如:

void print(int a) {cout << "Integer: " << a << endl;
}void print(double a) {cout << "Double: " << a << endl;
}int main() {print(5);       // 調用 print(int)print(3.14);    // 調用 print(double)return 0;
}

在這個例子中,print(5) 完全匹配 print(int a)print(3.14) 完全匹配 print(double a)

2. 類型轉換的匹配

如果沒有找到完全匹配的重載版本,編譯器會嘗試進行類型轉換,以便找到最合適的函數。例如:

void print(int a) {cout << "Integer: " << a << endl;
}void print(double a) {cout << "Double: " << a << endl;
}int main() {print(5.5);  // 5.5 是 double 類型,編譯器會將它自動轉換成 int 類型調用 print(int)return 0;
}

編譯器會將 5.5 轉換為 int 類型并調用 print(int a)

3. 最小化轉換

編譯器會選擇最少轉換的重載版本。如果一個重載版本需要更多的類型轉換,它的優先級較低。例如:

void print(int a) {cout << "Integer: " << a << endl;
}void print(double a) {cout << "Double: " << a << endl;
}void print(float a) {cout << "Float: " << a << endl;
}int main() {print(5);       // 調用 print(int)print(5.0);     // 調用 print(double)print(5.0f);    // 調用 print(float)return 0;
}

對于 print(5),編譯器會優先選擇 print(int a),而不會選擇 print(double a)print(float a),因為它不需要進行類型轉換。

4. 函數重載的最優匹配

如果兩個重載版本都符合條件,編譯器會選擇最符合的版本。例如:

void print(int a) {cout << "Integer: " << a << endl;
}void print(char* a) {cout << "String: " << a << endl;
}void print(void* a) {cout << "Pointer: " << a << endl;
}int main() {print(5);         // 調用 print(int)print("hello");   // 調用 print(char*)print(NULL);      // 調用 print(void*)return 0;
}

這就是函數重載中最優匹配的規則:print(5) 顯式調用了 print(int)print("hello") 調用了 print(char*),而 print(NULL) 則選擇了 print(void*),因為 NULL 是一個指針常量。

重載函數常見問題

雖然函數重載非常有用,但在實際開發中,仍然存在一些潛在問題,我們需要注意。

1. 重載歧義

如果編譯器無法明確選擇最合適的重載版本,程序就會發生歧義,導致編譯錯誤。例如:

void print(int a) { cout << "Integer: " << a << endl; }
void print(double a) { cout << "Double: " << a << endl; }int main() {print(5);    // 編譯錯誤,編譯器無法確定調用 print(int) 還是 print(double)return 0;
}

原因:如果我們傳遞 5,它既可以被轉換成 int 類型,也可以轉換成 double 類型,編譯器無法決定調用哪個版本的函數,從而導致歧義。

解決方法:避免傳遞可以隱式轉換為多種類型的參數,或者明確指明調用的函數版本:

2. 默認參數與重載

在某些情況下,默認參數可能與函數重載發生沖突。比如:

void print(int a = 0) { cout << "Integer: " << a << endl; }
void print(double a) { cout << "Double: " << a << endl; }int main() {print();     // 編譯錯誤:默認參數與重載函數沖突return 0;
}

原因print() 會被解釋為 print(int a),但默認值 a = 0 又使得 print()print(int) 發生重載沖突。

3. 函數重載與運算符重載的沖突

運算符重載與函數重載可能會產生一些混淆。特別是在運算符重載函數的參數類型與普通函數重載函數的參數類型非常接近時,會出現歧義。

函數重載的優化技巧

1. 避免不必要的重載

在一些情況下,函數重載會導致代碼冗余,增加維護的難度。例如,如果兩個重載函數之間只有一個小的差別,考慮將它們合并為一個函數,利用 可變參數模板 來實現。

void print(int a) { cout << "Integer: " << a << endl; }
void print(double a) { cout << "Double: " << a << endl; }// 使用模板重載函數
template<typename T>
void print(T a) {cout << "Value: " << a << endl;
}int main() {print(10);      // 調用 print<int>print(3.14);    // 調用 print<double>return 0;
}
2. 使用 std::variantstd::any 代替過多的重載

如果你的函數重載僅僅是為了支持多種數據類型的處理,可以考慮使用 std::variantstd::any 來避免過多的重載。

#include <iostream>
#include <variant>void print(std::variant<int, double, std::string> value) {std::visit([](auto&& arg) { std::cout << arg << std::endl; }, value);
}int main() {print(10);           // 輸出: 10print(3.14);         // 輸出: 3.14print("Hello");      // 輸出: Helloreturn 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/70091.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70091.shtml
英文地址,請注明出處:http://en.pswp.cn/web/70091.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

14-H指數

給你一個整數數組 citations &#xff0c;其中 citations[i] 表示研究者的第 i 篇論文被引用的次數。計算并返回該研究者的 h 指數。 根據維基百科上 h 指數的定義&#xff1a;h 代表“高引用次數” &#xff0c;一名科研人員的 h 指數 是指他&#xff08;她&#xff09;至少發…

關于es6-module的語法

ES6&#xff08;ECMAScript 2015&#xff09;引入了模塊化的概念&#xff0c;旨在使 JavaScript 更加模塊化、可維護和可重用。ES6 模塊允許我們在不同的文件中組織和管理代碼&#xff0c;使得不同模塊之間的依賴關系更加清晰。 1. 導出&#xff08;Export&#xff09; 1.1 命…

Chrome多開終極形態解鎖!「窗口管理工具+IP隔離插件

Web3項目多開&#xff0c;繼ads指紋瀏覽器錢包被盜后&#xff0c;更多人采用原生chrome瀏覽器&#xff0c;當然對于新手&#xff0c;指紋瀏覽器每月成本也是一筆不小開支&#xff0c;今天逛Github發現了這樣一個解決方案&#xff0c;作者開發了窗口管理工具IP隔離插件&#xff…

DeepSeek核心算法解析:如何打造比肩ChatGPT的國產大模型

注&#xff1a;此文章內容均節選自充電了么創始人&#xff0c;CEO兼CTO陳敬雷老師的新書《自然語言處理原理與實戰》&#xff08;人工智能科學與技術叢書&#xff09;【陳敬雷編著】【清華大學出版社】 文章目錄 DeepSeek大模型技術系列一DeepSeek核心算法解析&#xff1a;如何…

arm 入坑筆記

1.開發環境&#xff08;IDE&#xff09;使用keil_5 (keil_mdk) 2.兩個手冊需要關注&#xff1a;用戶手冊&#xff08;編程需要&#xff09;&#xff0c;數據手冊&#xff08;硬件&#xff09; 3.32bit地址空間&#xff1a;0~2^324GB尋址空間及&#xff08;0-FFFF_FFFF&#x…

弱監督語義分割學習計劃(0)-計劃制定

經過與deepseek的一番討論和交流&#xff0c;DeepSeek為我設計了一個30天高強度學習計劃&#xff0c;重點聚焦弱監督/無監督語義分割在野外場景的應用&#xff0c;結合理論與實踐&#xff0c;并最終導向可落地的開源項目。以下是詳細計劃&#xff1a; 總體策略 優先級排序&…

vscode遠程報錯:Remote host key has changed,...

重裝了Ubuntu系統之后&#xff0c;由20.04改為22.04&#xff0c;再用vscode遠程&#xff0c;就出現了以上報錯。 親測有效的辦法 gedit ~/.ssh/known_hosts 打開這個配置文件 刪掉與之匹配的那一行&#xff0c;不知道刪哪一行的話&#xff0c;就打開第一行這個 /.ssh/confi…

Python - 爬蟲利器 - BeautifulSoup4常用 API

文章目錄 前言BeautifulSoup4 簡介主要特點&#xff1a;安裝方式: 常用 API1. 創建 BeautifulSoup 對象2. 查找標簽find(): 返回匹配的第一個元素find_all(): 返回所有匹配的元素列表select_one() & select(): CSS 選擇器 3. 訪問標簽內容text 屬性: 獲取標簽內純文本get_t…

DeepSeek驅動下的數據倉庫范式轉移:技術解耦、認知重構與治理演進

DeepSeek驅動下的數據倉庫范式轉移&#xff1a;技術解耦、認知重構與治理演進 ——基于多場景實證的架構革命研究 一、技術解耦&#xff1a;自動化編程范式的演進 1.1 語義驅動的ETL生成機制 在金融風控場景中&#xff0c;DeepSeek通過動態語法樹解析&#xff08;Dynamic Syn…

代碼隨想錄算法訓練營day38(補0206)

如果求組合數就是外層for循環遍歷物品&#xff0c;內層for遍歷背包。 如果求排列數就是外層for遍歷背包&#xff0c;內層for循環遍歷物品。 1.零錢兌換 題目 322. 零錢兌換 給你一個整數數組 coins &#xff0c;表示不同面額的硬幣&#xff1b;以及一個整數 amount &#xff0c…

golang channel底層實現?

底層數據實現 type hchan struct { qcount uint // 當前隊列中的元素數量 dataqsiz uint // 環形隊列的大小 buf unsafe.Pointer // 指向環形隊列的指針 elemsize uint16 // 元素大小 closed uint32 // chan…

圖的最小生成樹算法: Prim算法和Kruskal算法(C++)

上一節我們學習了最短路徑算法, 這一節來學習最小生成樹. 最小生成樹(Minimum Spanning Tree, MST)算法是圖論中的一種重要算法, 主要用于在加權無向圖中找到一棵生成樹, 使得這棵樹包含圖中的所有頂點, 并且所有邊的權重之和最小. 這樣的樹被稱為最小生成樹. 最小生成樹廣泛應…

矩陣系統源碼搭建的數據管理開發功能解析,支持OEM

一、引言 在矩陣系統中&#xff0c;數據猶如血液&#xff0c;貫穿整個系統的運行。高效的數據管理開發功能是確保矩陣系統穩定、可靠運行的關鍵&#xff0c;它涵蓋了數據的存儲、處理、安全等多個方面。本文將深入探討矩陣系統源碼搭建過程中數據管理功能的開發要點。 二、數據…

DeepSeek 助力 Vue 開發:打造絲滑的日期選擇器(Date Picker),未使用第三方插件

前言&#xff1a;哈嘍&#xff0c;大家好&#xff0c;今天給大家分享一篇文章&#xff01;并提供具體代碼幫助大家深入理解&#xff0c;徹底掌握&#xff01;創作不易&#xff0c;如果能幫助到大家或者給大家一些靈感和啟發&#xff0c;歡迎收藏關注哦 &#x1f495; 目錄 Deep…

操作系統知識點2

1.P&#xff0c;V操作可以實現進程同步&#xff0c;進程互斥&#xff0c;進程的前驅關系 2.先來先服務調度算法是不可搶占的算法 3.UNIX操作系統中&#xff0c;對文件系統中空閑區的管理通常采用成組鏈接法 4.對于FAT32文件系統&#xff0c;它采用的是鏈接結構 5.不同的I/O…

【個人開發】deepspeed+Llama-factory 本地數據多卡Lora微調【完整教程】

文章目錄 1.背景2.微調方式2.1 關鍵環境版本信息2.2 步驟2.2.1 下載llama-factory2.2.2 準備數據集2.2.3 微調模式2.2.3.1 zero-1微調2.2.3.2 zero-2微調2.2.3.3 zero-3微調2.2.3.4 單卡Lora微調 2.2.4 實驗2.2.4.1 實驗1&#xff1a;多GPU微調-zero12.2.4.2 實驗2&#xff1a;…

iOS 中使用 FFmpeg 進行音視頻處理

在 iOS 中使用 FFmpeg 進行音視頻處理,通常需要將 FFmpeg 的功能集成到項目中。由于 FFmpeg 是一個 C 庫,直接在 iOS 中使用需要進行一些配置和封裝。 1. 在 iOS 項目中集成 FFmpeg 方法 1:使用 FFmpeg 預編譯庫 下載 FFmpeg iOS 預編譯庫: 可以從以下項目中獲取預編譯的 …

Elasticsearch:將 Ollama 與推理 API 結合使用

作者&#xff1a;來自 Elastic Jeffrey Rengifo Ollama API 與 OpenAI API 兼容&#xff0c;因此將 Ollama 與 Elasticsearch 集成非常容易。 在本文中&#xff0c;我們將學習如何使用 Ollama 將本地模型連接到 Elasticsearch 推理模型&#xff0c;然后使用 Playground 向文檔提…

openGauss 3.0 數據庫在線實訓課程18:學習視圖管理

前提 我正在參加21天養成好習慣| 第二屆openGauss每日一練活動 課程詳見&#xff1a;openGauss 3.0.0數據庫在線實訓課程 學習目標 掌握openGauss視圖的管理&#xff1a;創建視圖、刪除視圖、查詢視圖的信息、修改視圖的信息。 課程作業 1.創建表&#xff0c;創建普通視圖…

騰訊云大模型知識引擎×DeepSeek賦能文旅

騰訊云大模型知識引擎DeepSeek賦能文旅 ——以合肥文旅為例的技術革新與實踐路徑 一、技術底座&#xff1a;知識引擎與DeepSeek的融合邏輯 騰訊云大模型知識引擎與DeepSeek模型的結合&#xff0c;本質上是**“知識庫檢索增強生成&#xff08;RAG&#xff09;實時聯網能力”**…