7 函数重载

1 C++ 中的函数重载

  • 函数重载(Function Overload)

    • 用同一个函数名定义不同的函数
    • 当函数名和不同的参数搭配时函数的含义不同
  • 示例

    • Demo

      #include <stdio.h>
      #include <string.h>
      
      int func(int x)
      {
          return x;
      }
      
      int func(int a, int b)
      {
          return a + b;
      }
      
      int func(const char* s)
      {
          return strlen(s);
      }
      
      
      int main(int argc, char *argv[])
      {
          printf("%d
      ", func(3));  //3
          printf("%d
      ", func(4, 5));  //9
          printf("%d
      ", func("ABCD"));  //4
          
          return 0;
      }
      
  • 函数重载至少满足下面的一个条件

    • 参数个数不同
    • 参数类型不同
    • 参数顺序不同

2 函数默认参数与函数重载

  • 函数默认参数遇到函数重载会发生什么?

    • Demo

      #include <stdio.h>
      
      int func(int a, int b, int c = 0)
      {
          return a * b * c;
      }
      
      int func(int a, int b)
      {
          return a + b;
      }
      
      
      int main(int argc, char *argv[])
      {
          int c = func(1, 2);
          
          printf("c = %d
      ",c);
          
          return 0;
      }
      
    • 编译

      test.cpp:15:21: error: call of overloaded ‘func(int, int)’ is ambiguous
           int c = func(1,2);
                           ^
      test.cpp:3:5: note: candidate: int func(int, int, int)
       int func(int a,int b,int c = 0)
           ^
      test.cpp:8:5: note: candidate: int func(int, int)
       int func(int a,int b)
           ^
      
  • 编译器调用重载函数的准则

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

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

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

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

    • 重载函数在本质上是相互独立的不同函数
    • 重载函数的函数类型不同
    • 函数返回值不能作为函数重载的依据,函数重载是由函数名参数列表决定的
  • 示例:函数重载的本质

    • Demo

      #include <stdio.h>
      
      int add(int a, int b)  // int(int, int)
      {
          return a + b;
      }
      
      int add(int a, int b, int c) // int(int, int, int)
      {
          return a + b + c;
      }
      
      int main()
      {
          printf("%p
      ", (int(*)(int, int))add);
          printf("%p
      ", (int(*)(int, int, int))add);
      
          return 0;
      }
      
    • 编译运行

      0x804840b
      0x8048418
      

3 重载与指针

  • 问题:下面的函数指针将保存哪个函数的地址?

    • 第一个
    int func(int x)
    {
        return x;
    }
    
    int func(int a,int b)
    {
        return a + b;
    }
    
    int func(const char* s)
    {
        return strlen(s);
    }
    
    typedef int(*PFUNC)(int a);
    
    int c = 0;
    
    PFUNC p = func;
    
    c = p(1);  //1
    
  • 函数重载遇到函数指针:将重载函数名赋值给函数指针

    • 根据重载规则挑选与函数指针参数列表一致的候选者
    • 严格匹配候选者的函数类型与函数指针的函数类型
  • 示例:函数重载 VS 函数指针

    • Demo

      #include <stdio.h>
      #include <string.h>
      
      int func(int x)
      {
          return x;
      }
      
      int func(int a, int b)
      {
          return a + b;
      }
      
      int func(const char* s)
      {
          return strlen(s);
      }
      
      typedef double(*PFUNC)(int a);  //函数指针,无法匹配
      
      
      int main(int argc, char *argv[])
      {
          int c = 0;
      
          PFUNC p = func;
              
          c = p(1);   
          
          printf("c = %d
      ", c);
      
          return 0;
      }
      
    • 编译

      test.cpp: In function ‘int main(int, char**)’:
      test.cpp:26: error: no matches converting function ‘func’ to type ‘double (*)(int)’
      test.cpp:4: error: candidates are: int func(int)
      test.cpp:9: error:                 int func(int, int)
      test.cpp:14: error:                 int func(const char*)
      
  • 注意

    • 函数重载必然发生在同一个作用域中

    • 编译器需要用参数列表函数类型进行函数选择,不考虑返回值,但是当遇到函数指针时,需要考虑函数类型(参数,返回值),需要严格匹配

    • 无法直接通过函数名得到重载函数的入口地址

      • Demo

        #include <stdio.h>
        
        int add(int a, int b)  // int(int, int)
        {
            return a + b;
        }
        
        int add(int a, int b, int c) // int(int, int, int)
        {
            return a + b + c;
        }
        
        int main()
        {
            printf("%p
        ", add);
            printf("%p
        ", add);
        
            return 0;
        }
        
      • 编译

        test.cpp: In function ‘int main()’:
        test.cpp:15: error: overloaded function with no contextual type information
        test.cpp:16: error: overloaded function with no contextual type information
        
      • 修改:利用强制类型转换

        #include <stdio.h>
        
        int add(int a, int b)  // int(int, int)
        {
            return a + b;
        }
        
        int add(int a, int b, int c) // int(int, int, int)
        {
            return a + b + c;
        }
        
        int main()
        {
            printf("%p
        ", (int(*)(int, int))add);  //强制类型转换为函数指针:int(*)(int, int)
            printf("%p
        ", (int(*)(int, int, int))add);//强制类型转换为函数指针:int(*)(int, int,int)
        
            return 0;
        }
        

4 C++ 和 C 相互调用

  • 实际工程中 C++ 和 C 代码相互调用是不可避免的

  • C++ 编译器能够兼容 C 语言的编译方式

  • C++ 编译器会优先使用 C++ 编译的方式

  • extern 关键字能够强制让 C++ 编译器进行 C 方式的编译

    extern "C"
    {
        //do C-style compilation here
    }
    
  • 示例:

    • Demo

      //add.h
      int add(int a, int b);
      
      
      //add.c
      #include "add.h"
      
      int add(int a, int b)
      {
          return a + b;
      }
      
      
      //main.c
      #include <stdio.h>
      
      #include "add.h"
      
      int main()
      {
          int c = add(1, 2);
          
          printf("c = %d
      ", c);
          
          return 0;
      }
      
    • 编译

      /tmp/ccnrEzcf.o: In function `main':
      test.cpp:(.text+0x19): undefined reference to `add(int, int)'
      collect2: ld returned 1 exit status
      
    • 修正

      //add.h
      int add(int a, int b);
      
      
      //add.c
      #include "add.h"
      
      int add(int a, int b)
      {
          return a + b;
      }
      
      
      //main.c
      #include <stdio.h>
      extern "C" 
      {
          #include "add.h"
      }
      
      int main()
      {
          int c = add(1, 2);
          
          printf("c = %d
      ", c);
          
          return 0;
      }
      
    • 编译运行

      3
      
  • 问题:如何保证一段 C 代码只会被以 C 的方式被编译?

    • __cplusplus 是 C++ 编译器内置的标准宏定义
    • __cplusplus 的意义:确保 C 代码以统一的 C 方式被编译成目标文件
    #ifdef __cplusplus
    extern "C"{
    #endif
        
    //C-style Compilation
      
    #ifdef __ cplusplus  
    }
    #endif
    
  • 示例:C++ 调用 C 函数

    • Demo

      //main.c
      #include <stdio.h>
      
      
      #ifdef __cplusplus
      extern "C" {
      #endif
      
      #include "add.h"
      
      #ifdef __cplusplus
      }
      #endif
      
      
      int main()
      {
          int c = add(1, 2);
          
          printf("c = %d
      ", c);  //3
          
          return 0;
      }
      
    • C 语言编译器:gcc main.c 通过

    • C++ 编译器:g++ main.c 通过

  • 注意

    • C++ 编译器不能以 C 的方式编译重载函数

    • 编译方式决定函数名被编译后的目标名

      • C++ 编译方式将函数名参数列表编译成目标名

      • C 编译方式只将函数名作为目标名进行编译

        • Demo

          int add(int a,int b)
          {
              return a + b;
          }
          
          int add(int a,int b,int c)
          {
              return a + b + c;
          }
          
        • C++ 方式编译:g++ -c test.cpp -o test.oo -> nm test.oo

          00000000 T _Z3addii
          0000000e T _Z3addiii
                   U __gxx_personality_v0
          
        • C 方式编译

          extern "C"
          {
          int add(int a,int b)
          {
              return a + b;
          }
          
          int add(int a,int b,int c)
          {
              return a + b + c;
          }
          }
          
        • 编译:g++ -c test.cpp -o test.oo

          test.cpp: In function ‘int add(int, int, int)’:
          test.cpp:8: error: declaration of C function ‘int add(int, int, int)’ conflicts with
          test.cpp:3: error: previous declaration ‘int add(int, int)’ here
          
原文地址:https://www.cnblogs.com/bky-hbq/p/13708830.html