前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >c++之重载函数学习总结

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

作者头像
用户6280468
发布于 2022-03-21 06:30:13
发布于 2022-03-21 06:30:13
41100
代码可运行
举报
文章被收录于专栏:txp玩Linuxtxp玩Linux
运行总次数:0
代码可运行

一、C++中的函数重载:

1、函数重载的概念:

  • 用同一个函数名定义不同的函数
  • 当函数名和不同的参数搭配时函数的含义不同
  • 注意:在c语言中是没有函数重载这个概念的。

代码示例演示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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语言编译器里面编译是会报错的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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语言里面不支持函数重载。

2、函数重载至少要满足下面的一个条件:

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

比如下面两个函数可以构造重载函数吗?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int func (int a,const char* s)
{
   return a;
}

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

答案肯定是可以构造重载函数的,读者可以自己试试(这个比较好理解)。

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

例如下面的两个函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int func(int a, int b, int c =0)
{
    return a*b*c;
}
int func(int a, int b)
{
   return a+b;
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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(意思是梦棱两可的),也就是说默认参数这种使用时不允许的。

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

  • 将所有同名函数作为候选者
  • 尝试寻找可行的候选函数:
  • 精确匹配实参

通过默认参数能够匹配实参

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

  • 匹配失败:

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

无法匹配所有候选者,函数未定义编译失败

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

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

代码测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@txp-virtual-machine:/home/txp# ./a.out
0x40052d
0x400541

从输出结果我们可以看出这两个函数的入口地址不一样,这表明这两个函数是不同的函数。

6、小结:

  • 函数重载是c++中引入的概念
  • 函数重载的本质是相互独立的不同函数
  • c++中通过函数名和函数参数确定函数调用

二、重载函数进阶学习

1、重载与指针:

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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函数

函数重载遇上函数指针:

  • 将函数名赋值给函数指针时
  • 根据重载规则跳线与函数指针参数列表一致的候选者
  • 严格匹配候选者的函数类型与函数指针的函数类型

代码试验:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@txp-virtual-machine:/home/txp# ./a.out
c=2

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

2、注意:

  • 函数重载必然发生在同一个作用域中
  • 编译器需要用参数列表或者函数类型进行函数选择(也就是说碰到指针,要注意函数类型了)

无法直接通过函数名得到重载函数的入口地址,这里还是通过上面的例子演示一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);

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

  • 实际工程中C++和c代码相互调用是不可避免的
  • c++编译器能够兼容c语言的编译方式
  • c++编译器会优先使用c++编译的方式

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
extern "c"
{


}

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

add.c内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

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

{

    return a + b;

}

add.h内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int add(int a, int b);

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
    int c = add(1, 2);
    
    printf("c = %d\n", c);
    
    return 0;
}

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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文件里面是否生成符号表(有生成):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@txp-virtual-machine:/home/txp/add# nm add.o
0000000000000000 T add

解决方法,main.cpp改成:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

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

}


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

    return 0;
}

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@txp-virtual-machine:/home/txp/add# ./a.out
c = 3

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
extern "C"
{
   int add(int a, int b);

}

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


编译输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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文件内容改成:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{ 
     int c =0;
     c = add(2,3);
     printf("c=%d\n",c);
     return 0;
}

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@txp-virtual-machine:/home/txp/add# gcc add.c test.o
root@txp-virtual-machine:/home/txp/add# ./a.out
c=5

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

解决方法如下:

  • __cplusplus是c++编译器内置的标准宏定义
  • __cplusplus的意义,确保c代码以统一的c方式被编译成目标文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ifdef __cplusplus
extern "C"
{
  #endif

  #ifdef __cplusplus
}
#endif

这里把main.cpp改成:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@txp-virtual-machine:/home/txp/add# g++ main.cpp add.o
root@txp-virtual-machine:/home/txp/add# ./a.out
c = 3

4、注意事项

  • C++编译器不能以c的方式编译重载函数
  • 编译方式决定函数名被编译后的目标名
  • c++编译方式将函数名和参数列表编译成目标名,这里举个例子main.cpp:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int add(int a, int b)
{
  return a+b;
}

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

编译输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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为例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
extern "C"
{
   int add(int a, int b)
  {
       return a+b;
  }

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

输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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)

目标名起冲突所以报错。

5、小结:

  • 函数重载是c++对c的一个重要升级
  • 函数重载通过参数列表区分不同的同名函数
  • extern关键字能够实现c和c++的相互调用
  • 编译方式决定符号表中的函数名的最终目标名

四、总结:

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 txp玩Linux 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C++之类模板的深入学习总结
注解:当需要重载函数模板时,优先考虑使用模板特化;当模板特化无法满足需求,再使用函数重载
用户6280468
2022/03/21
2540
C++之友元的学习总结
注意:func() 全局函数是 Test 类的友元,func() 可以访问Test 类的所有成员,但是 func() 不是 Test 的成员函数。
用户6280468
2022/03/21
2480
C++之友元的学习总结
c++学习之析构函数和const总结,你真的掌握了吗?
大家好,今天再次写c++的文章,首先给各位网友说明一下这段时间为啥都是写c++的文章,没有Linux的文章;原因是这样的,自己立了一个flag,八月份把c++的基本语法全部过完(目前完成三分之一),所以文章过程中我写的可能没有很详细的解释一些概念;所以文章中有不理解的地方,可以私聊我,我会尽力解答好。同时昨天遇到一位刚高考完的网友,人家都这么努力学习,你还打酱油吗?
用户6280468
2022/03/21
2510
c++学习之析构函数和const总结,你真的掌握了吗?
C++之类的继承关系学习总结(一)
组合关系,从字面上来理解的话,就是谁也离不开谁,必须相互组合在一起才行,例如我们生活当中的电脑组成:
用户6280468
2022/03/21
3240
C++之类的继承关系学习总结(一)
我的C++奇迹之旅相遇:支持函数重载的原理
函数重载概念 函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
学习起来吧
2024/04/02
1540
我的C++奇迹之旅相遇:支持函数重载的原理
C++之函数模板的深入理解学习总结
在昨天的文章里面,我们给大家简单的分享了关于c++里面的函数模板的概念,通过代码示例,我们对函数模板的优势有了一个比较清楚的认识。咋们今天继续来深入学习函数模板。以下内容是今天知识学习总结笔记。
用户6280468
2022/03/21
2570
C++之函数模板的深入理解学习总结
C++之类成员函数重载学习总结
从上面回顾重载函数的知识中,我们要注意到一点函数重载必须发生在同一作用域里面(其他两点问题不大),所以的构造函数和普通成员函数是可以构造重载的,而与全局函数是不可以构成重载的。
用户6280468
2022/03/21
5480
C++之操作符重载学习总结
1、我们先来看一个问题实现,下面的复数解决方案是否可行,复数大家应该都不陌生(分为实部和虚部):
用户6280468
2022/03/21
2710
c++中的构造函数学习总结(一)
大家晚上好,今天给大家分享的是c++中的构造函数,这段时间可能分享c++、Uboot、linux内核的文章会比较多一点,自己的拖延症太强了,得改掉这个坏习惯来。每天进步一点点,日积月累你也是专家。
用户6280468
2022/03/21
6750
4.C++中的函数重载,C++调用C代码,new/delete关键字,namespace(命名空间)
可以看到输出结果,每个函数的入口地址都不一样(重载函数的入口地址,必须使用强制转换来获取)
诺谦
2019/05/24
8690
C++之类模板的概念学习总结
我们在前面的两篇文章里面,对函数模板有了一个清楚的认识,作为类比学习,当然泛型的思想是可以应用到类上的。
用户6280468
2022/03/21
4420
C语言之const和volatile"究极"学习
关于const的用法,现在大概前前后后应该写了有两篇文章,以前学习的时候,用法体会不是那么深刻,为啥这么说呢,因为在学习c++的时候,会发现const关键字有新的玩法,关于这个新的玩法,大家可以去看最近学习总结写的c++文章专辑。
用户6280468
2022/03/21
4070
C语言之const和volatile"究极"学习
C++从入门到精通——函数重载
函数重载是指在同一个作用域内,可以定义多个名称相同但参数列表不同的函数。这些函数具有不同的参数个数、类型或顺序,以便编译器能够根据传入的参数来确定调用哪个函数。函数重载使得代码更加简洁,避免了命名上的冗余,并提高了代码的可读性和可维护性。通过重载,我们可以为不同的操作或数据类型提供统一的接口,使得函数的使用更加灵活和方便。
鲜于言悠
2024/03/30
1.5K0
C++从入门到精通——函数重载
C++之标准库的学习总结
从上面我们可以看到,不直接使用printf函数去打印这个值,这个以前在书上,都是直接讲解把数值说送到输出流中去,但是你一开始学习cout函数(或者说你还没有接触到对象的时候,根本不明白这什么意思);如果进行了左移的重载之后,那么程序将产生神奇的变化,所以在 main() 中不用 printf() 和格式化字符串 '\n' 了,因为编译器会通过重载的机制会为我们选择究竟使用哪一个重载机制。
用户6280468
2022/03/21
5090
C++之标准库的学习总结
C++之静态成员变量和静态成员函数学习总结
平时我们在写类的时候,类中的成员变量,我们一般是通过对象名来访问public成员变量的,一般private(私有)的成员变量,对象是不能直接访问的;同时我们要明白每个对象的成员变量都是专属的,而且成员变量是不能在对象之间共享的,这就是专属性。下面我们来做一个小的程序需求来慢慢引出静态成员变量:
用户6280468
2022/03/21
6100
c++ 之三种继承方式的学习总结
在上一篇文章中我们已经接触到了protect这个关键字的作用了,今天我们继续深入继承的深入学习。
用户6280468
2022/03/21
2700
c++ 之三种继承方式的学习总结
再论C++中的const和引用
今天给大家分享一下这段时间学习c++的总结学习:c++里面的const关键字和引用。
用户6280468
2022/03/21
4350
C++之拷贝构造函数的浅copy和深copy
当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空;换句话来说,就是我们在类中,不用我们程序猿自己写,编译就自动提供了无参构造函数(只是我们肉眼看不到!)
用户6280468
2022/03/21
4110
C++之拷贝构造函数的浅copy和深copy
C++之初始化列表学习总结
1、在介绍列表之前,我们先来看看使用const关键字来修饰类中的成员会有什么事情发生,下面是一段简单代码:
用户6280468
2022/03/21
2450
C++之函数模板的概念和意义
我们再用使用函数的方式来实现这个功能,当然以前我们在c语言里面使用指针传参方式来实现这种两个数值直接的交换,现在我们利用c++里面更加高级的方式来实现,就是使用引用来实现(不过它的本质还是指针来实现,只是我们只用引用再不用去考虑指针的细节了)
用户6280468
2022/03/21
4500
C++之函数模板的概念和意义
相关推荐
C++之类模板的深入学习总结
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文