1.函数重载(Function Overloading)
函数重载是一种允许在同一个作用域内定义多个具有相同名称但参数列表(指的是形参列表)不同的函数的特性。换句话说,如果在同一作用域内的几个函数名字相同但形参列表不同,我们称这几个函数为重载函数。主要用于提高代码的可读性和灵活性,避免为类似功能的函数取多个不同的名字。
接下来我借助两个生活中的例子来帮助大家更好的理解函数重载:
🏠 生活中的“函数重载”——同一个“动作”,不同的“方式”
想象你在家里喊 “打开” 这个指令,它可以有不同的含义,取决于你说话的对象和额外的信息:
1️⃣ 你对智能音箱说:“打开” → 它会默认打开客厅的灯 💡
2️⃣ 你对冰箱说:“打开” → 你会拉开冰箱门,拿取食物 🥬
3️⃣ 你对电视说:“打开” → 电视屏幕亮起,开始播放节目 📺
4️⃣ 你对车钥匙说:“打开” → 车门解锁,可以上车 🚗💡 总结:
尽管“打开”这个指令名字相同,但根据不同的对象(参数),执行的具体操作不同,这就像函数重载一样,同一个函数名,根据参数的不同执行不同的功能!😃亦或者用“咖啡机”类比函数重载 ☕️
想象你在一家咖啡店,店里的**咖啡机(CoffeeMachine)有一个“制作咖啡”**的按钮,但是这个按钮可以处理不同的参数,制作不同类型的咖啡。
1️⃣ 按钮的多种使用方式(函数重载)
💡 咖啡机的
makeCoffee()
按钮可以重载成多个版本:
- 无参数版本:默认制作一杯普通美式咖啡。
- 一个参数(口味):可以指定咖啡类型,比如拿铁、卡布奇诺。
- 两个参数(口味 + 奶泡):可以指定是否加奶泡。
- 三个参数(口味 + 奶泡 + 糖量):还能调整甜度。
2️⃣ 代码示例
#include <iostream> using namespace std; class CoffeeMachine { public: // 1️⃣ 无参数:默认美式 void makeCoffee() { cout << "制作了一杯普通美式咖啡 ☕️" << endl; } // 2️⃣ 一个参数:指定咖啡类型 void makeCoffee(string type) { cout << "制作了一杯 " << type << " ☕️" << endl; } // 3️⃣ 两个参数:指定咖啡类型 + 是否加奶泡 void makeCoffee(string type, bool foam) { cout << "制作了一杯 " << type; if (foam) cout << "(加奶泡)"; cout << " ☕️" << endl; } // 4️⃣ 三个参数:咖啡类型 + 是否加奶泡 + 糖量 void makeCoffee(string type, bool foam, int sugar) { cout << "制作了一杯 " << type; if (foam) cout << "(加奶泡)"; cout << ",加 " << sugar << " 份糖 🍬" << endl; } }; int main() { CoffeeMachine machine; machine.makeCoffee(); // 调用无参数版本 machine.makeCoffee("拿铁"); // 调用1个参数版本 machine.makeCoffee("卡布奇诺", true); // 调用2个参数版本 machine.makeCoffee("摩卡", false, 2); // 调用3个参数版本 return 0; }
3️⃣ 运行结果
制作了一杯普通美式咖啡 ☕️ 制作了一杯 拿铁 ☕️ 制作了一杯 卡布奇诺(加奶泡) ☕️ 制作了一杯 摩卡,加 2 份糖 🍬
4️⃣ 现实世界的对应关系
现实世界(咖啡机) C++ 函数重载 同一个按钮(makeCoffee) 同一个函数名( makeCoffee
)按不同的方式按按钮 传入不同的参数 制作不同口味的咖啡 调用不同的重载版本
总结
函数重载就像一台智能咖啡机,同一个按钮(函数名),可以根据不同的参数组合(咖啡类型、奶泡、糖量)做出不同的咖啡(执行不同的逻辑),提高了代码的灵活性和可读性。
是不是很直观?😃
2.关键特性
- 相同的函数名:多个函数名称相同,易于理解和记忆。
- 不同的参数列表(必须满足以下至少一个条件):
- 参数的个数不同。
- 参数的类型不同。
- 参数的顺序不同(仅当参数类型不同)。
- 返回值类型不能作为区分依据,仅凭返回值不同不能构成重载。
仅靠返回值不同不能构成函数重载,编译器无法仅通过返回值来区分重载函数。
🚨 错误示例:仅靠返回值不同
#include <iostream> using namespace std; int getValue() { return 10; } // ❌ 仅返回值不同,编译报错 double getValue() { return 20.5; } int main() { cout << getValue() << endl; return 0; }
🛑 错误原因
编译器无法通过
getValue();
这样的调用来确定应该执行哪个版本的getValue()
,因为调用时没有提供参数,它无法仅通过返回值来推断。
🔹 结论
- 仅靠返回值不同不能构成函数重载(编译器无法区分)。
- 参数列表必须不同(参数个数或类型不同)。
- 函数重载是基于参数匹配,而不是基于返回值匹配。
3. 函数重载示例
3.1. 基本数学运算的函数重载(加法、乘法等)
适用于相同操作作用于不同类型的情况,例如 add()
可用于 int
、double
或 std::string
(字符串拼接)。
#include<iostream>
#include<vector>
#include<string>
// 重载add函数
int add(int a,int b){
return a+b;
}
double add(double a,double b){
return a+b;
}
std::string add(std::string a,std::string b){
return a+b;
}
int main(){
std::cout<<add(1,2)<<std::endl; // 输出:3
std::cout<<add(1.1,2.2)<<std::endl;// 输出:3.3
std::cout<<add("hello","my")<<std::endl;// 输出:hellomy,hellomy是一个const char类型
return 0;
}
3.2 构造函数重载(为不同参数初始化对象)
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public:
// 默认构造函数
Point() {
x = 0;
y = 0;
}
// 带参数的构造函数
Point(int a, int b) {
x = a;
y = b;
}
// 打印点的信息
void display() {
cout << "Point(" << x << ", " << y << ")" << endl;
}
};
int main() {
Point p1; // 调用默认构造函数
Point p2(3, 4); // 调用带参数构造函数
p1.display(); // 输出 Point(0, 0)
p2.display(); // 输出 Point(3, 4)
return 0;
}
3.3 运算符重载(比如 +
号的重载)
运算符重载是特殊的函数重载,用于定义类对象的运算行为。
#include <iostream>
using namespace std;
class Complex {
private:
double real, imag;
public:
Complex(double r, double i) : real(r), imag(i) {}
// 重载 + 运算符
Complex operator+(const Complex& c) {
return Complex(real + c.real, imag + c.imag);
}
void display() {
cout << real << " + " << imag << "i" << endl;
}
};
int main() {
Complex c1(2, 3), c2(4, 5);
Complex c3 = c1 + c2; // 调用 operator+()
c3.display(); // 输出 6 + 8i
return 0;
}