c++之重载函数学习总结


1、C++中的函数重载:c++

一、函数重载的概念:web

  • 用同一个函数名定义不一样的函数vim

  • 当函数名和不一样的参数搭配时函数的含义不一样微信

  • 注意:在c语言中是没有函数重载这个概念的编辑器

代码示例演示:函数

#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()
{

   return 0;

}

上面在c++编译器里面编译时没有问题的,若是放在c语言编译器里面编译是会报错的:学习

root@txp-virtual-machine:/home/txp# gcc test5.c
test5.c:8:5: error: conflicting types for ‘func’
 int func(int a, int b)
     ^
test5.c:3:5: note: previous definition of ‘func’ was here
 int func(int x)
     ^
test5.c:13:5: error: conflicting types for ‘func’
 int func(const char* s)
     ^
test5.c:3:5: note: previous definition of ‘func’ was here
 int func(int x)

因此说c语言里面不支持函数重载。测试

二、函数重载至少要知足下面的一个条件:ui

  • 参数个数不一样url

  • 参数类型不一样

  • 参数顺序不一样

好比下面两个函数能够构造重载函数吗?

int func (int a,const char* s)
{
   return a;
}

int func(const char*s,int a)
{
    return strlen(s)
}

答案确定是能够构造重载函数的,读者能够本身试试(这个比较好理解)。

三、当函数默认参数赶上函数重载会发生什么?

例以下面的两个函数:

int func(int a, int b, int c =0)
{
    return a*b*c;
}
int func(int a, int b)
{
   return a+b;
}

到底会发生啥,咱们仍是看下面这个实验:

#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);
    
    return 0;
}

运行结果:

root@txp-virtual-machine:/home/txp# g++ test5.cpp
test5.cpp: In function ‘int main(int, char**)’:
test5.cpp:16:22: error: call of overloaded ‘func(int, int)’ is ambiguous
     int c = func(1, 2);
                      ^
test5.cpp:16:22: note: candidates are:
test5.cpp:3:5: note: int func(int, int, int)
 int func(int a, int b, int c = 0)
     ^
test5.cpp:8:5: note: int func(int, int)
 int func(int a, int b)

从上面报错的结果里面有一个单词ambiguous(意思是梦棱两可的),也就是说默认参数这种使用时不容许的。

四、C++编译器调用重载函数的准则:

  • 将全部同名函数做为候选者

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

  • 精确匹配实参

       经过默认参数可以匹配实参

      经过默认类型转换匹配实参

  • 匹配失败:

      最终寻找到的候选函数不惟一,则出现二义性,编译失败

      没法匹配全部候选者,函数未定义编译失败

五、函数重载的注意事项:

  • 重载函数在本质上是相互独立的不一样函数

  • 重载函数的函数类型不一样

  • 函数返回值不能做为函数重载的依据

  • 函数重载是由函数名和参数列表决定的

代码测试:

#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\n", (int(*)(int, int))add);
    printf("%p\n", (int(*)(int, int, int))add);

    return 0;
}

运行结果:

root@txp-virtual-machine:/home/txp# ./a.out
0x40052d
0x400541

从输出结果咱们能够看出这两个函数的入口地址不同,这代表这两个函数是不一样的函数。

六、小结:

  • 函数重载是c++中引入的概念

  • 函数重载的本质是相互独立的不一样函数

  • c++中经过函数名和函数参数肯定函数调用

2、重载函数进阶学习

一、重载与指针:

下面的函数指针将保存哪一个函数的地址?

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(2)//到底选择哪一个func函数

函数重载赶上函数指针:

  • 将函数名赋值给函数指针时

  • 根据重载规则跳线与函数指针参数列表一致的候选者

  • 严格匹配候选者的函数类型与函数指针的函数类型

代码试验:

#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 int(*PFUNC)(int a);

int main(int argc,char *argv[])
{
     int c =0;
     PFUNC p =func;

     c = p(2);
     printf("c=%d\n",c);
     return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# ./a.out
c=2

从输出结果来看,很明显调用了第一个func函数。

二、注意:

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

  • 编译器须要用参数列表或者函数类型进行函数选择(也就是说碰到指针,要注意函数类型了)

没法直接经过函数名获得重载函数的入口地址,这里仍是经过上面的例子演示一下:

#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\n", add);
    printf("%p\n", add);

    return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp# g++ test5.cpp
test5.cpp: In function ‘int main()’:
test5.cpp:15:23: error: overloaded function with no contextual type information
     printf("%p\n", add);
                       ^
test5.cpp:16:23: error: overloaded function with no contextual type information
     printf("%p\n", add);

3、C++和C相互调用:

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

  • c++编译器可以兼容c语言的编译方式

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

extern关键字可以强制让C++编译器进行c方式的编译:

extern "c"
{


}

一、下面进行一个c++中调用c函数,这里我在当前建立三个文件:add.c 、add.h 、main.cpp。内容分别以下:

add.c内容:


#include "add.h"
int add(int a, int b)

{

    return a + b;

}

add.h内容:

int add(int a, int b);

而后我用gcc编译编译生成add.o文件:

root@txp-virtual-machine:/home/txp/add# vim add.c
root@txp-virtual-machine:/home/txp/add# vim add.h
root@txp-virtual-machine:/home/txp/add# gcc -c add.c -o add.o
root@txp-virtual-machine:/home/txp/add# ls
add.c  add.h  add.o

而后main.cpp里面调用add.c

#include <stdio.h>
int main()
{
    int c = add(1, 2);
    
    printf("c = %d\n", c);
    
    return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp/add# g++ main.cpp add.o
/tmp/ccqz3abQ.o: In function `main':
main.cpp:(.text+0x13): undefined reference to `add(int, int)'

collect2: error: ld returned 1 exit status


结果显示找不到这个函数,为了可以在c++里面调用c语言里面的函数,咱们就要使用刚才上面讲的第四点了;这里咱们先用nm命令来查看一下add.o文件里面是否生成符号表(有生成):

root@txp-virtual-machine:/home/txp/add# nm add.o
0000000000000000 T add

解决方法,main.cpp改为:

#include <stdio.h>

extern "c"
{
    #include "add.h"

}


int main()
{
    int c = add(1, 2);
    
    printf("c = %d\n", c);

    return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp/add# ./a.out
c = 3

二、c中如何调用c++函数:

这里我把main.cpp的内容改为:

extern "C"
{
   int add(int a, int b);

}

int add(int a, int b)
{
    return a+b;    
}


编译输出:

root@txp-virtual-machine:/home/txp/add# g++ -c main.cpp -o test.o
root@txp-virtual-machine:/home/txp/add# nm -s test.o
0000000000000000 T add


add.c文件内容改为:

#include <stdio.h>
int main()

     int c =0;
     c = add(2,3);
     printf("c=%d\n",c);
     return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp/add# gcc add.c test.o
root@txp-virtual-machine:/home/txp/add# ./a.out
c=5

三、如何保证一段c代码只会以c的方式被编译?

解决方法以下:

  • __cplusplus是c++编译器内置的标准宏定义

  • __cplusplus的意义,确保c代码以统一的c方式被编译成目标文件

#ifdef __cplusplus
extern "C"
{
  #endif

  #ifdef __cplusplus
}
#endif

这里把main.cpp改为:

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

#include "add.h"

#ifdef __cplusplus
}
#endif

int main()
{
    int c = add(1, 2);
    
    printf("c = %d\n", c);
    
    return 0;
}

输出结果:

root@txp-virtual-machine:/home/txp/add# g++ main.cpp add.o
root@txp-virtual-machine:/home/txp/add# ./a.out
c = 3

四、注意事项

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

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

  • c++编译方式将函数名和参数列表编译成目标名,这里举个例子main.cpp:

int add(int a, int b)
{
  return a+b;
}

int add(int a, int b , int c)
{
   return a+b+c;
}

编译输出:

root@txp-virtual-machine:/home/txp/add# g++ -c main.cpp -o test.oo
root@txp-virtual-machine:/home/txp/add# nm test.oo
0000000000000000 T _Z3addii
0000000000000014 T _Z3addiii

说明ii表示两个参数,iii表示三个参数

  • c编译方式只将函数名做为目标名进行编译,这里仍是以main.cpp为例:

extern "C"
{
   int add(int a, int b)
  {
       return a+b;
  }

  int add(int a, int b , int c)
   {
      return a+b+c;
   }
}

输出结果:

root@txp-virtual-machine:/home/txp/add# g++ -c main.cpp -o test.oo
main.cpp: In function ‘int add(int, int, int)’:
main.cpp:8:29: error: declaration of C function ‘int add(int, int, int)’ conflicts with
 int add(int a, int b , int c)
                             ^
main.cpp:3:5: error: previous declaration ‘int add(int, int)’ here
 int add(int a, int b)

目标名起冲突因此报错。

五、小结:

  • 函数重载是c++对c的一个重要升级

  • 函数重载经过参数列表区分不一样的同名函数

  • extern关键字可以实现c和c++的相互调用

  • 编译方式决定符号表中的函数名的最终目标名

4、总结:


好了,今天的分享就到这里,若是文章中有错误或者不理解的地方,能够交流互动,一块儿进步。我是txp,下期见!

本文分享自微信公众号 - TXP嵌入式(txp1121518wo-)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索