17、函数重载

厨子大约 4 分钟C++C++基础编程程序厨

函数重载是C++的一项重要特性,通过函数重载,可以在同一个作用域内定义多个同名函数,但这些函数的参数列表必须不同(参数类型、参数个数或参数顺序不同)。

函数重载的规则

  1. 函数名相同: 重载的函数必须使用相同的函数名。
  2. 参数列表不同: 重载的函数必须有不同的参数列表,包括参数类型、参数个数或参数顺序。
  3. 返回值类型不影响重载: 仅返回值类型不同,不能构成函数重载。

函数重载的解析

当调用一个重载函数时,编译器会根据实际传递的参数类型、个数和顺序,选择最匹配的函数版本进行调用,如果找不到最匹配的,编译器会认为有歧义,报错。

示例代码:

#include <iostream>
using namespace std;

// 1. 参数个数不同
void print(int a) {
    cout << "Printing an integer: " << a << endl;
}

void print(int a, int b) {
    cout << "Printing two integers: " << a << ", " << b << endl;
}

// 2. 参数类型不同
void print(double a) {
    cout << "Printing a double: " << a << endl;
}

void print(const string& str) {
    cout << "Printing a string: " << str << endl;
}

// 3. 参数顺序不同
void print(int a, double b) {
    cout << "Printing an integer and a double: " << a << ", " << b << endl;
}

void print(double a, int b) {
    cout << "Printing a double and an integer: " << a << ", " << b << endl;
}

int main() {
    print(10);          // 调用 void print(int a)
    print(10, 20);      // 调用 void print(int a, int b)
    print(3.14);        // 调用 void print(double a)
    print("Hello");     // 调用 void print(const string& str)
    print(10, 3.14);    // 调用 void print(int a, double b)
    print(3.14, 10);    // 调用 void print(double a, int b)

    return 0;
}

进阶知识点

运算符重载: 运算符重载本质上也是函数重载,它允许为用户自定义类型定义运算符的行为。

C++中,参数类型是否 const不会产生函数重载。这是因为 const 修饰符作用于参数时,只是限制了函数内部对参数值的修改,而不会改变参数的类型本身。

因此,以下两个函数声明会被认为是重复定义,而不是重载:

void func(int a);         // 1
void func(const int a);   // 2: 错误,重复定义,不是重载

编译器会将上述两个函数视为完全相同的函数签名,因此会导致编译错误。

const 修饰值参数

对于值传递的参数(如 int a),const 只是限制函数内部不能修改参数的值,但不会影响函数的外部行为。因此,以下两个函数声明是等价的:

void func(int a);         // 1
void func(const int a);   // 2: 与 1 等价

编译器会将它们视为相同的函数签名,因此无法重载。

const 修饰指针或引用参数

对于指针或引用参数,const 的位置不同会产生不同的语义,因此可以形成重载:

  • const 修饰指针指向的内容:

    • void func(int* p);         // 1: 接受普通指针
      void func(const int* p);   // 2: 接受指向常量的指针
      
    • 这两个函数可以重载,因为参数类型不同(int*const int*)。

  • const 修饰引用:

    • void func(int& r);         // 1: 接受普通引用
      void func(const int& r);   // 2: 接受常量引用
      
    • 这两个函数也可以重载,因为参数类型不同(int&const int&)。

const 修饰成员函数

对于类的成员函数,const 修饰的是成员函数本身,而不是参数。这种 const 会影响函数签名,因此可以形成重载:

class MyClass {
public:
    void func() { std::cout << "Non-const func\n"; }        // 1
    void func() const { std::cout << "Const func\n"; }      // 2
};

这里,func()func() const 是两个不同的函数,可以重载。调用时,编译器会根据对象的 const 属性选择正确的版本:

MyClass obj;
const MyClass constObj;

obj.func();        // 调用 void func()
constObj.func();   // 调用 void func() const

练习

  1. 编写一个程序,定义三个重载函数 max(),分别用于求两个整数、两个浮点数和三个整数中的最大值。

  2. 编写一个程序,定义一个函数模板 swap(),用于交换两个变量的值,并使用该模板交换两个整数、两个浮点数和两个字符串的值。

  3. 编写一个程序,定义一个类 Point,表示二维平面上的点,并重载 + 运算符,实现两个点的加法运算。

  4. 以下代码是否能编译通过?如果不能,为什么?

    1. void func(int a);
      void func(const int a);
      
  5. 编写一个程序,定义一个函数 print,使其能够重载以下调用:

    1. print(int* p)
    2. print(const int* p)
    3. print(int& r)
    4. print(const int& r)
  6. 定义一个类 String,并重载 operator[],使其支持以下调用:

    1. char& operator[](int index);
    2. const char& operator[](int index) const;