C++ 中的函数重载(Function Overloading)允许在同一作用域内定义多个同名函数,只要它们的参数列表不同。这是 C++ 多态性的一种体现,使得函数调用更加直观和灵活。
函数重载的基本概念
重载的基本规则
函数重载基于函数签名的不同,函数签名包括:
- 函数名
- 参数的数量
- 参数的类型
- 参数的顺序
注意:返回类型不是函数签名的一部分!
// 合法的重载:参数数量不同
void print(int x) {
std::cout << "Integer: " << x << std::endl;
}
void print(int x, int y) {
std::cout << "Two integers: " << x << ", " << y << std::endl;
}
// 合法的重载:参数类型不同
void print(double x) {
std::cout << "Double: " << x << std::endl;
}
void print(const std::string& s) {
std::cout << "String: " << s << std::endl;
}
void print(char c) {
std::cout << "Character: " << c << std::endl;
}
// 非法的重载:仅返回类型不同
int getValue();
// double getValue(); // 错误!仅返回类型不同
int main() {
print(42); // 调用 print(int)
print(3.14); // 调用 print(double)
print("hello"); // 调用 print(const std::string&)
print('A'); // 调用 print(char)
print(1, 2); // 调用 print(int, int)
return 0;
}
参数顺序的重载
void process(int x, double y) {
std::cout << "int, double: " << x << ", " << y << std::endl;
}
void process(double x, int y) {
std::cout << "double, int: " << x << ", " << y << std::endl;
}
int main() {
process(1, 2.0); // 调用 process(int, double)
process(1.0, 2); // 调用 process(double, int)
// process(1, 2); // 二义性错误!编译器无法确定调用哪个
return 0;
}
重载解析(Overload Resolution)
编译器选择最佳匹配函数的过程称为重载解析,遵循以下优先级:
1. 精确匹配
void func(int x) { std::cout << "int" << std::endl; }
void func(double x) { std::cout << "double" << std::endl; }
int main() {
func(42); // 精确匹配 func(int)
func(3.14); // 精确匹配 func(double)
return 0;
}
2. 类型提升
void func(int x) { std::cout << "int" << std::endl; }
void func(double x) { std::cout << "double" << std::endl; }
int main() {
char c = 'A';
short s = 100;
func(c); // char 提升为 int
func(s); // short 提升为 int
func(3.14f); // float 提升为 double
return 0;
}
3. 标准转换
void func(int x) { std::cout << "int" << std::endl; }
void func(double x) { std::cout << "double" << std::endl; }
int main() {
func(3.14); // 如果没有 double 版本,会转换为 int(有损转换)
return 0;
}
4. 用户定义转换
class Complex {
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
operator double() const { return real; } // 转换运算符
};
void func(int x) { std::cout << "int" << std::endl; }
void func(Complex c) { std::cout << "Complex" << std::endl; }
int main() {
func(3.14); // double -> Complex(构造函数转换)
return 0;
}
引用和指针的重载
左值引用和右值引用重载
#include <iostream>
#include <utility>
void process(int& x) {
std::cout << "LValue reference: " << x << std::endl;
}
void process(const int& x) {
std::cout << "Const LValue reference: " << x << std::endl;
}
void process(int&& x) {
std::cout << "RValue reference: " << x << std::endl;
}
int main() {
int a = 10;
const int b = 20;
process(a); // 调用 process(int&)
process(b); // 调用 process(const int&)
process(30); // 调用 process(int&&)
process(std::move(a)); // 调用 process(int&&)
return 0;
}
指针的重载
void func(int* p) {
std::cout << "int pointer" << std::endl;
}
void func(const int* p) {
std::cout << "const int pointer" << std::endl;
}
void func(int* const p) { // 这与 func(int* p) 相同!
std::cout << "int const pointer" << std::endl;
}
int main() {
int x = 10;
const int y = 20;
func(&x); // 调用 func(int*)
func(&y); // 调用 func(const int*)
return 0;
}
const 重载
成员函数的 const 重载
class MyString {
char* data;
size_t length;
public:
MyString(const char* str) {
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
}
~MyString() { delete[] data; }
// const 版本:返回 const 引用
const char& operator[](size_t index) const {
std::cout << "const version called" << std::endl;
return data[index];
}
// 非 const 版本:返回非 const 引用
char& operator[](size_t index) {
std::cout << "non-const version called" << std::endl;
return data[index];
}
// const 成员函数重载
void print() const {
std::cout << "const print: " << data << std::endl;
}
void print() {
std::cout << "non-const print: " << data << std::endl;
}
};
int main() {
MyString str("Hello");
const MyString constStr("World");
str[0] = 'h'; // 调用非 const 版本
char c = constStr[0]; // 调用 const 版本
str.print(); // 调用非 const 版本
constStr.print(); // 调用 const 版本
return 0;
}
const 重载的实现技巧
class Container {
std::vector<int> data;
public:
// const 版本
const int& at(size_t index) const {
if (index >= data.size()) {
throw std::out_of_range("Index out of range");
}
return data[index];
}
// 非 const 版本:复用 const 版本的逻辑
int& at(size_t index) {
return const_cast<int&>(
static_cast<const Container*>(this)->at(index)
);
}
};
模板函数重载
模板与非模板函数重载
// 非模板函数
void func(int x) {
std::cout << "Non-template: " << x << std::endl;
}
// 模板函数
template<typename T>
void func(T x) {
std::cout << "Template: " << x << std::endl;
}
// 特化的模板函数
template<>
void func<double>(double x) {
std::cout << "Specialized template: " << x << std::endl;
}
int main() {
func(42); // 调用非模板版本(精确匹配优先)
func(3.14); // 调用特化模板版本
func('A'); // 调用通用模板版本
func<int>(42); // 显式调用模板版本
return 0;
}
模板参数的重载
// 不同数量的模板参数
template<typename T>
void process(T value) {
std::cout << "Single template parameter" << std::endl;
}
template<typename T, typename U>
void process(T first, U second) {
std::cout << "Two template parameters" << std::endl;
}
// 模板参数的约束(C++20)
template<typename T>
requires std::integral<T>
void process(T value) {
std::cout << "Integral type" << std::endl;
}
template<typename T>
requires std::floating_point<T>
void process(T value) {
std::cout << "Floating point type" << std::endl;
}
运算符重载
成员函数 vs 非成员函数
class Complex {
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// 成员函数重载
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// 前置递增
Complex& operator++() {
++real;
return *this;
}
// 后置递增
Complex operator++(int) { // int 参数区分前置和后置
Complex temp = *this;
++real;
return temp;
}
friend std::ostream& operator<<(std::ostream& os, const Complex& c);
};
// 非成员函数重载
std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << "(" << c.real << ", " << c.imag << ")";
return os;
}
// 支持不同类型的运算
Complex operator+(double d, const Complex& c) {
return Complex(d + c.real, c.imag);
}
int main() {
Complex c1(1, 2);
Complex c2(3, 4);
Complex c3 = c1 + c2; // 成员函数
Complex c4 = 5.0 + c1; // 非成员函数
std::cout << c3 << std::endl;
std::cout << ++c1 << std::endl; // 前置递增
std::cout << c1++ << std::endl; // 后置递增
return 0;
}
特殊运算符重载
class SmartPointer {
int* ptr;
public:
SmartPointer(int* p = nullptr) : ptr(p) {}
~SmartPointer() { delete ptr; }
// 解引用运算符
int& operator*() const {
return *ptr;
}
// 成员访问运算符
int* operator->() const {
return ptr;
}
// 下标运算符
int& operator[](size_t index) const {
return ptr[index];
}
// 函数调用运算符
int operator()(int x, int y) const {
return x + y;
}
// 类型转换运算符
operator bool() const {
return ptr != nullptr;
}
explicit operator int*() const {
return ptr;
}
};
int main() {
SmartPointer sp(new int(42));
std::cout << *sp << std::endl; // 解引用
std::cout << sp(10, 20) << std::endl; // 函数调用
if (sp) { // 隐式转换为 bool
std::cout << "Pointer is valid" << std::endl;
}
int* raw = static_cast<int*>(sp); // 显式转换
return 0;
}
重载的陷阱和最佳实践
避免二义性
// 危险:可能导致二义性
void func(int x) { }
void func(double x) { }
int main() {
// func(3.14f); // 二义性!float 可以转换为 int 或 double
// 解决方案:显式转换
func(static_cast<int>(3.14f));
func(static_cast<double>(3.14f));
return 0;
}
默认参数与重载
// 危险:默认参数可能导致二义性
void func(int x) { }
void func(int x, int y = 0) { }
int main() {
// func(42); // 二义性!可以匹配两个函数
func(42, 10); // OK,明确匹配第二个函数
return 0;
}
最佳实践
// 1. 保持重载函数的语义一致
class Printer {
public:
void print(int x) { std::cout << x; }
void print(double x) { std::cout << x; }
void print(const std::string& s) { std::cout << s; }
// 所有 print 函数都执行"打印"操作
};
// 2. 避免过度重载
// 不好:过多的重载版本
void process(int);
void process(double);
void process(float);
void process(long);
void process(short);
// 更好:使用模板
template<typename T>
void process(T value) {
// 统一处理逻辑
}
// 3. 使用 enable_if 进行条件重载(C++11)
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type
process(T value) {
std::cout << "Processing integer: " << value << std::endl;
}
template<typename T>
typename std::enable_if