一、函數重載:同名函數的 “差異化生存”?
1. 概念定義?
函數重載(Function Overloading)是 C++ 的重要特性,指在同一作用域內,允許存在多個同名函數,但要求這些函數的參數列表必須不同。
(參數個數、參數類型、參數順序至少有一項不同)非常重要!!。
編譯器會根據調用時傳入的實參,自動匹配到對應的函數,實現 “一個函數名,多種功能” 的效果。?
2. 典型案例分析?
案例 1:參數個數不同的重載?
#include <iostream>
using namespace std;// 無參數版本
void print() {cout << "無參數調用" << endl;
}// 1個int參數版本
void print(int a) {cout << "int參數:" << a << endl;
}// 2個int參數版本
void print(int a, int b) {cout << "兩個int參數:" << a << " " << b << endl;
}int main() {print(); // 匹配無參數版本print(10); // 匹配1個int參數版本print(20, 30); // 匹配2個int參數版本return 0;
}
?輸出結果:?
無參數調用
int參數:10
兩個int參數:20 30
案例 2:參數類型不同的重載?
?
#include <iostream>
using namespace std;// int類型參數
int add(int a, int b) {return a + b;
}// double類型參數
double add(double a, double b) {return a + b;
}int main() {cout << "int加法:" << add(3, 5) << endl; // 匹配int版本,輸出8cout << "double加法:" << add(2.5, 4.5) << endl; // 匹配double版本,輸出7.0return 0;
}
注意:僅返回值類型不同的函數,不能構成重載。例如int add(int a)和double add(int a),編譯器無法通過調用語句(如add(10))區分,會報 “重定義” 錯誤。?
案例 3:參數順序不同的重載?
#include <iostream>?#include <string>?using namespace std;??// 先int后string?void showInfo(int age, string name) {?cout << "年齡:" << age << ",姓名:" << name << endl;?}??// 先string后int?void showInfo(string name, int age) {?cout << "姓名:" << name << ",年齡:" << age << endl;?}??int main() {?showInfo(20, "張三"); // 匹配先int后string版本?showInfo("李四", 22); // 匹配先string后int版本?return 0;?}??
輸出結果:?
?
年齡:20,姓名:張三?姓名:李四,年齡:22??
案例 4:多文件分離(聲明與定義分離)?
實際項目中,函數重載常涉及多文件拆分,需注意 “聲明與定義的一致性”。?
#ifndef FUNC_H
#define FUNC_H // 防止頭文件重復包含// 聲明3個重載函數
void calculate(int a);
void calculate(double a);
void calculate(int a, double b);#endif
#include "func.h"
#include <iostream>
using namespace std;void calculate(int a) {cout << "int參數計算:" << a * 2 << endl;
}void calculate(double a) {cout << "double參數計算:" << a * 3 << endl;
}void calculate(int a, double b) {cout << "int+double參數計算:" << a + b << endl;
}
#include "func.h"
int main() {calculate(5); // 匹配int版本,輸出10calculate(3.5); // 匹配double版本,輸出10.5calculate(2, 4.8); // 匹配int+double版本,輸出6.8return 0;
}
編譯運行:需將三個文件一起編譯(如g++ main.cpp func.cpp -o test),確保聲明的重載函數在定義文件中都有對應的實現,否則會報 “未定義引用” 錯誤。?
3. 原理:為什么 C++ 支持,C 語言不支持??
核心原因在于編譯器對函數名的 “修飾規則” 不同:?
- C 語言:編譯器會直接使用函數原名作為最終的 “符號名”(如函數add(int a, int b),符號名就是add)。若存在同名函數,符號名重復,鏈接階段會報錯,因此 C 語言不支持函數重載。?
- C++ 語言:編譯器會根據函數的參數列表對函數名進行 “修飾”(也稱 “命名粉碎”,Name Mangling),生成唯一的符號名。例如:?
- add(int a, int b)可能被修飾為_Z3addii(3表示函數名長度,ii表示兩個 int 參數);?
- add(double a, double b)可能被修飾為_Z3adddd。?
不同重載函數的修飾后符號名不同,編譯器和鏈接器能準確識別,因此 C++ 支持函數重載。?
4.引用:變量的 “別名” 與權限控制?
1. 概念定義?
引用(Reference)是 C++ 引入的新特性,本質是變量的別名,它與原變量共享同一塊內存空間,對引用的操作等同于對原變量的操作。語法格式為:類型& 引用名 = 原變量;。?
注意:引用必須在定義時初始化,且初始化后不能再指向其他變量(與指針的核心區別)。?
2. 基礎操作:定義與使用?
?
#include <iostream>?using namespace std;??int main() {?int a = 10;?int& ref_a = a; // 定義引用ref_a,作為a的別名??cout << "a的值:" << a << endl; // 輸出10?cout << "ref_a的值:" << ref_a << endl; // 輸出10(與a共享內存)??ref_a = 20; // 操作引用,等同于修改a?cout << "修改后a的值:" << a << endl; // 輸出20??cout << "a的地址:" << &a << endl; // 輸出a的地址(如0x7ffeefbff4ac)?cout << "ref_a的地址:" << &ref_a << endl; // 輸出相同地址(證明共享內存)?return 0;?}??
3. 權限控制:放大、縮小與平移?
引用的權限遵循 “不能放大原變量的權限” 原則,否則編譯器會報錯;權限縮小或平移是允許的。以下是典型案例:?
案例 1:權限平移(同權限引用)?
原變量是普通變量,引用也為普通引用,權限一致,合法。?
?
int a = 10;?int& ref_a = a; // 合法:普通變量→普通引用,權限平移?
?
案例 2:權限縮小(原變量權限 > 引用權限)?
原變量是普通變量(可讀可寫),引用為const引用(只讀),權限縮小,合法。?
?
int a = 10;?const int& ref_a = a; // 合法:普通變量→const引用,權限縮小??ref_a = 20; // 錯誤:const引用只讀,不能修改?a = 20; // 正確:原變量是普通變量,可修改(修改后ref_a的值也會變)??
案例 3:權限放大(原變量權限 < 引用權限)?
原變量是const變量(只讀),引用為普通引用(可讀可寫),權限放大,非法。?
?
const int a = 10; // a是const變量,只讀?int& ref_a = a; // 錯誤:const變量→普通引用,權限放大,編譯器報錯??
案例 4:臨時變量的引用(易混淆點)?
臨時變量(如表達式結果、字面量)的權限是 “只讀”,只能用const引用接收,否則會觸發權限放大錯誤。?
?// 錯誤案例:臨時變量→普通引用(權限放大)?int& ref1 = 10; // 錯誤:10是臨時變量,只讀,普通引用無法接收?int& ref2 = 3 + 5; // 錯誤:3+5的結果是臨時變量,只讀??// 正確案例:臨時變量→const引用(權限縮小)?const int& ref3 = 10; // 合法:const引用可接收臨時變量?const int& ref4 = 3 + 5; // 合法:臨時變量值為8,ref4指向該臨時變量??
易錯點總結?
- 引用未初始化:定義引用時必須綁定原變量,否則報錯。?
錯誤:int& ref;(編譯器提示 “引用必須初始化”)。?
- 引用指向臨時變量未加 const:如上述案例 4,臨時變量只能用const引用接收,普通引用會觸發權限放大錯誤。?
- 混淆引用與指針:引用初始化后不能改指向,指針可以改指向;引用不需要解引用(*),指針需要。?
錯誤:int a=10, b=20; int& ref=a; ref=&b;(試圖讓引用指向 b,編譯器報錯)。?
- 數組引用的語法錯誤:數組引用需指定數組大小,語法格式為類型 (&引用名)[數組大小] = 原數組;。?
錯誤:int arr[5] = {1,2,3,4,5}; int& ref_arr = arr;(未指定數組大小);?
正確:int (&ref_arr)[5] = arr;。?
總結?
- 函數重載:C++ 通過 “參數列表不同” 實現同名函數的重載,核心原理是編譯器對函數名的 “修飾規則”(根據參數列表生成唯一符號名),而 C 語言因無此修飾,不支持重載。?
- 引用:本質是變量的別名,需初始化且不可改指向;權限控制遵循 “不能放大” 原則,臨時變量需用const引用接收,避免權限相關錯誤。