C++函数重载

简介: 函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。

函数重载

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。


要注意的是:只有函数名相同,形参不同(个数\类型\类型顺序不同)才能构成函数重载

而函数名相同,返回值不同的函数不构成函数重载


返回值类型与函数是否重载无关


参数类型不同

int add(int a, int b)
{
  cout << "int:" << a + b << endl;
  return a + b;
}
double add(double a, double b)
{
  cout << "double:" << a + b << endl;
  return a + b;
}
int main()
{
  add(1,1);
  add(1.1,2.2);
}



参数个数不同

void fun(int a)
{
  cout << a << endl;
}
void fcun(int a, int b)
{
  cout << a <<" "<< b << endl;
}
int main()
{
  fun(1);
  fun(1,2);
}


参数类型顺序不同

这里注意:是参数类型顺序不同,而不是参数名顺序不同

int f(int a,double b)和int f(int b,double a)是不构成重载的
void ff(int a, char b)
{
  cout << a << " " << b << endl;
}
void ff(char a, int b)
{
  cout << a << " " << b << endl;
}
int main()
{
  ff(10,'a');
  ff('a',10);
}


1

以上三个情况就是各种类型的函数重载


其实还有一种情况,就是当重载和缺省在一起时:


void fff()
{
  cout << 1 << endl;
}
void fff(int a = 0)
{
  cout << a << endl;
}


上面2个函数都可以通过编译

当我们使用实参对缺省参数赋值fff(1),可以正常运行

但是无参调用时会出现歧义,会报错

fff(),编译器不知道是要调用无参的那么函数还是调用缺省参数函数,发生冲突,无法运行


函数重载是怎样实现的

C语言不支持函数重载,而C++却能支持,C++是如何支持的呢?


这其实是在编译链接过程中,利用函数名修饰规则实现的


我们先来看一下编译链接的过程,如果我们在test.h中声明了函数,在test.cpp中实现,在_test.cpp文件中调用

实验代码如下:


test.h
#include <iostream>
using namespace std;
int add(int a, int b);
double add(double a, double b);
1
2
3
4
5
test.cpp
#include "test.h"
int add(int a, int b)
{
  return a + b;
}
double add(double a, double b)
{
  return a + b;
}


_test.cpp
#include "test.h"
int main()
{
  add(1,1);
  add(1.1, 2.2);
  return 0;
}


编译链接过程如下图:







4fdc821435834acc9a52ff35a288b31d.png


调用函数都会被转换成call+一个地址,这个地址就是函数的地址



fd2235a36fb9445b8ab9dfc11d54a505.png





所以,这段代码在编译过程中,需要call2次,本来call需要去找到函数的地址,但是函数的定义在test.cpp文件中,地址也在test.i文件中,当前还未链接,所以还找不到地址




c45d2035c49e4744a496eadd7b6dc3bc.png



下面接着编译链接,在链接时,会生成一个符号表,这里面有函数名和其地址,这时2个文件是链接在一起的了

,之后就会进行找函数地址操作


但是C语言中,规定的是通过函数名进行寻址,因为这里有2个姓名相同的函数名,所以找不到正确的地址

所以C语言才不支持函数重载


下面,我们也通过linux系统,给;能够更方便得观察到函数名修饰规则


我们先在linux环境下创建一个c语言文件test.c






283a74457b6c4a0ba30649be928253be.png



然后我们通过下面这些操作可以看到这个代码的汇编代码:



de5835a2ef2646c6a3d72acff6a9fddd.png



从汇编代码中找到调用func函数的部分:


bdf58dcd637f4ab88b7cbe3d4ea74e6d.png



这也证实了C语言是通过函数名进行寻址的


下面我们看一下C++是什么样的


先写一个cpp文件



987096a517a647139e682a1504f5c33a.png



然后还是观察它的汇编代码

可以看见汇编代码中,2个func的名字变了,这里不是func了





e92f5e6406a046be8b92ddc9c80baf4a.png


这其实就是函数名修饰规则


第一个调用的函数名是_Z4funci

-Z是编译器规定的长度

4是指函数名func的长度

func就是原函数命

最重要的就是i,它jiusint类型的缩写

同理,第二个函数名最后的id就是int和double类型的缩写


这里也能看出来为什么饭返回值不同不会构成函数重载?

因为返回值不会进入到函数名修饰规则里

参数会进入函数名修饰规则里,参数不同,最后函数名也不同


所以到这里就理解了为什么C++支持函数重载了


最后我们思考一个问题


如果我们把函数名修饰规则修改,允许返回值的类型以某种方式进入规则中,那么返回值不会是否会导致函数重载?


答案是也不可以


因为如果遇到如下的代码,2个函数的函数名相同,没有参数或参数都相同,只有返回值不同


int a()
{
  printf("int\n");
}
double a()
{
  printf("double\n");
}
int main()
{
  a();
  return 0;
}


这样到了汇编阶段,调用函数时返回值类型是体现不出来的,所以编译器也不知道到底是调用哪个函数

所以不论怎样,返回值类型不同不会导致函数重载

————————————————


目录
相关文章
|
1月前
|
存储 安全 编译器
【C++专栏】C++入门 | 函数重载、引用、内联函数
【C++专栏】C++入门 | 函数重载、引用、内联函数
27 0
|
1月前
|
编译器 Linux C语言
我的C++奇迹之旅相遇:支持函数重载的原理
我的C++奇迹之旅相遇:支持函数重载的原理
|
2月前
|
安全 编译器 Linux
【C++练级之路】【Lv.1】C++,启动!(命名空间,缺省参数,函数重载,引用,内联函数,auto,范围for,nullptr)
【C++练级之路】【Lv.1】C++,启动!(命名空间,缺省参数,函数重载,引用,内联函数,auto,范围for,nullptr)
|
2月前
|
程序员 C语言 C++
C++入门(头文件,命名空间,作用域,输入输出流,引用,缺省参数,函数重载)
C++入门(头文件,命名空间,作用域,输入输出流,引用,缺省参数,函数重载)
|
2月前
|
Linux C语言 C++
C++之函数重载【详解】
C++之函数重载【详解】
|
14天前
|
存储 安全 编译器
【C++入门】缺省参数、函数重载与引用(下)
【C++入门】缺省参数、函数重载与引用
|
14天前
|
编译器 C语言 C++
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
23 0
|
14天前
|
编译器 C语言 C++
【C++入门】缺省参数、函数重载与引用(上)
【C++入门】缺省参数、函数重载与引用
|
20天前
|
编译器 C++
C++函数重载详解
C++函数重载详解
8 1
|
27天前
|
存储 安全 编译器
【C++成长记】C++入门 |函数重载、引用、内联函数
【C++成长记】C++入门 |函数重载、引用、内联函数