函数重载的概念

同一个标识符在不同的上下文有不同的意义。函数重载用同一个函数名定义不同的函数当函数名和不同的参数搭配时函数的含义不同。

函数重载至少满足下面的一个条件:参数个数不同,参数类型不同,参数顺序不同。函数重载通常用于构造函数中不同场景下的初始化。

  1. int func(int x)
  2. {
  3. return x;
  4. }
  5. int func(int a, int b)
  6. {
  7. return a+b;
  8. }
  9. int func(const char* s)
  10. {
  11. return strlen(s);
  12. }

重载函数的本质是两个不同的函数,最终的符号表中存储的重载函数是不同标识的。

编译器调用重载函数的准则

  • 将所有同名函数作为候选者

  • 尝试寻找可行的候选函数

    • 精确匹配实参
    • 通过默认参数能够匹配实参
    • 通过默认类型转换匹配实参
  • 匹配失败

    • 最终寻找到的候选函数不唯一,则出现二义性,编译失败
    • 无法匹配所有候选者,函数未定义,编译失败

类成员函数的重载

像其他任意函数一样,成员函数(无论虚还是非虚)也可以重载。派生类可以重定义所有继承的0个或多个版本。通过前面的覆盖我们可以得到以下一些注意事项:

  • 如果派生类重新定义了重载成员,则通过派生类型只能访问派生类中定义的那些成员。


  • 如果派生类想通过自身类型使用所有的重载版本,则派生类型必须要么重定义所有重载版本,要么一个也不定义。


  1. class A {
  2. public:
  3. void hello(int a, int b) {
  4. cout << a << b <<endl;
  5. }
  6. };
  7. class B :public A {
  8. public:
  9. void hello(int a) {
  10. cout << a <<endl;
  11. }
  12. };
  13. int main(int argc, char *argv[]) {
  14. B b;
  15. b.hello(1, 1); // 报错
  16. return 0;
  17. }

运算符重载

C++ 运算符重载,本质上等于定义一个成员函数(实际上也可能是全局函数)。例如 a+b,本质上等同于调用函数「a.operator+(b)」,该函数的名字叫「operator+」

  1. struct Int {
  2. int value;
  3. // 重载加号运算符,本质上等于定义了
  4. // 一个名字叫「operator+」的函数。
  5. Int operator+(Int i)
  6. {
  7. return {value + i.value};
  8. }
  9. };
  10. int main() {
  11. Int a { 3 };
  12. Int b { 4 };
  13. // 调用+运算符,下面两行代码的用法完全等效
  14. //Int c = a + b;
  15. Int c = a.operator+(b);
  16. }
  1. #include <iostream>
  2. using namespace std;
  3. class A {
  4. public:
  5. A& operator<<(int num) {
  6. printf("%d", num);
  7. return *this;
  8. }
  9. };
  10. int main(int argc, char *argv[]) {
  11. A a;
  12. a << 1 << 2;
  13. return 0;
  14. }