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