[C/C++]详解C++的函数重载

Posted TT在长大

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C/C++]详解C++的函数重载相关的知识,希望对你有一定的参考价值。

什么是函数重载

在自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。

比如:一个经典段子,阿呆给领导送红包时,领导:“你这是什么意思?” 阿呆:“没什么意思,意思意思。” 领导:“那我就不好意思了。” 阿呆:“是我不好意思。” 领导:你肯定有什么意思。 阿呆:真的没有什么意思。 领导:既然没有什么意思,那你是什么意思? 阿呆:其实,我的意思就是想意思意思。

上面这个段子中的 ” 意思 “ 就是一个重载词。

函数重载的概念

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

例如希望交换两个变量的值long,这两个变量有多种类型,可以是 int、float、char、long 等。

#include<iostream>
using namespace std;

int Swap(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

char Swap(char *a, char *b)
{
	char temp = *a;
	*a = *b;
	*b = temp;
}

long Swap(long *a, long *b)
{
	long temp = *a;
	*a = *b;
	*b = temp;
}

float Swap(float *a, float *b)
{
	float temp = *a;
	*a = *b;
	*b = temp;
}

int main(){
    //交换 int 变量的值
    int n1 = 1, n2 = 2;
    Swap(&n1, &n2);
    cout<<n1<<", "<<n2<<endl;
   
    //交换 float 变量的值
    float f1 = 1223.335, f2 = 1236.943;
    Swap(&f1, &f2);
    cout<<f1<<", "<<f2<<endl;
   
    //交换 char 变量的值
    char c1 = 'A', c2 = 'D';
    Swap(&c1, &c2);
    cout<<c1<<", "<<c2<<endl;

    return 0;
}

需要注意,当用函数中用到缺省参数而参数类型没有改变就不属于函数重载,如:

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

int Add(int a, int b = 10)
{
	return a + b;
}

此时两个函数的参数类型顺序完全相同

只有返回类型不同也不属于函数重载,如:

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

short Add(int a, int b)
{
	return a + b;
}

名字修饰(Name Mangling)

C++是如何支持函数重载

在C/C++中,程序的运行需要经历 **预处理、编译、汇编、链接。**如下图所示:
程序的编译过程

  1. 在日常应用中项目通常是由多个头文件和多个源文件构成,如果当前a.cpp中调用了b.cpp中定义的Add函数时,编译后链接前,a.o的目标文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。

  2. 所以链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就会到b.o的符号表中找Add的地址,然后链接到一起。

  3. 在链接时,面对Add函数连接器会使用哪个名字,每个编译器都有自己的函数名修饰规则。下面我使用了g++演示这个修饰后的名字。
    重载两个Add
    如下图,对应的函数地址经过修饰后都是不相同的
    汇编
    我们可以看到在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。函数修饰后变成 _Z+函数长度+函数名+类型首字母

结论:C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。也再次印证了函数重载要求参数不同,而跟返回值没关系。

C语言为什么不支持函数重载

通过与上一节相同的方法在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。
gcc编译
这里也就解释了C语言没办法支持重载,原因是同名函数没办法区分。

extern “C”

在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,表示该函数按照C语言规则来编译。当C需要调用C++函数时,该C++函数也必须声明为extern “C”。

extern "C" int Add(int a, int b);

此时Add将不能重载。

总结

C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。

以上是关于[C/C++]详解C++的函数重载的主要内容,如果未能解决你的问题,请参考以下文章

C/C++编程笔记:C++多态性知识详解

C/C++: C++可调用对象详解

[C/C++]详解C++的多态

[C/C++]详解C++的多态

[C/C++]详解C++的类和对象

C/C++编程笔记:C++中的函数重载