文章目录
函数重载
1.概念
2.支持函数重载的原理
2.1准备知识
2.2原理
函数重载
1.概念
在C语言中,是不允许同名函数存在的。但是在一个作用域种,比如加法函数,想要实现各种类型的数据相加,要定义多个函数,但是这些函数实现的功能类似,却不可以同名,就非常麻烦。所以C++里面引入了函数重载这一概念,允许同名函数的存在。
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型
不同的问题。如下,就是函数重载,两个Add 函数的参数类型不同。
也可以是参数个数不同,如下
或者是参数的类型顺序不同,注意,是参数类型的顺序,如下:
但是,一定不可以是参数类型相同,但是变量名顺序不同,如下就是错误的。参数的名字变了,并没有本质上的改变,该是什么类型的还是什么类型,一定要是类型顺序不同。
2.支持函数重载的原理
2.1准备知识
首先我们要了解,一个.c 文件生成 .exe 文件的过程中,发生了什么。具体可以见这篇文章:【C语言】你知道.c文件是如何变成.exe文件的吗_Austerlitzl的博客-CSDN博客_
下图是编译链接过程的一个概括图。
下图是编译环境四个阶段。
1. 实际项目通常是由多个头文件和多个源文件构成,而通过对编译链接的了解,我们可以知道,【当前 main.c 中调用了 sum.c 中定义的 sum 函数时】,编译后链接前,main.o 的目标文件中没有 sum 的函数地址,因为 sum函数 是在 sum.c 中定义的,所以 sum 的地址在 sum.o 中。那么怎么办呢?
2. 所以链接阶段就是专门处理这种问题,链接器看到 main.o 调用 sum ,但是没有 sum 的地址,就会到 sum.o 的符号表中找 sum 的地址,然后链接到一起。
3. 那么链接时,面对 sum 函数,链接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则。
4. Windows下vs的修饰规则过于复杂,Linux下g++的修饰规则简单易懂,所以下面使用g++演示了这个修饰后的名字。
2.2原理
C++支持函数重载的原理就是——名字修饰。简单地说,一个C语言程序,如果对他进行编译,那么链接器在寻找一个函数的时候,是原原本本去寻找它的名字,如果写了相同名字的函数,编译器寻找的时候无法区分。但是,对于C++程序而言,会根据参数个数、参数类型对它的函数名进行一定程度上的修饰,这样即使是同名函数,由于参数个数或者参数类型或者参数类型顺序不同,修饰之后的函数名也是不同的,链接器就可以区分。
由于在不同环境下,修饰规则有所不同。而Linux环境下,函数名修饰规则比较简单,所以用Linux做演示,如下是C语言的函数调用,明显发现没有任何修饰。
但是如下是C++ 的程序,可以明显看出其函数名是被修饰的。其修饰规则也不难 _Z 是固定的,然后加上的数字是函数名长度,接着加上函数名,最后加上参数类型的首字母。
如果规定 C++ 的返回值也参与名字修饰呢?那么遇到同名函数的参数完全一致,但是返回值不同,是否也可以区分?
首先要清楚,如果其返回值也参与名字修饰,那么修饰之后的名字肯定也是不一样的,链接器肯定可以区分不同名字的函数。
但是,我们调用函数的时候,不一定每次都需要它的返回值,如下图,main() 函数里面调用两个Add 函数,但是谁知道它是调用返回值是 double 的,还是返回值是 int 的?所以不可取。
也可以看一下 VS 环境之下,只声明一个函数,却不定义,自然是找不到的,查看报错情况。如下是一个 C语言程序(红色箭头),其报错信息(最下面红色方框)可以看出,C语言确实没有名字修饰。
但是C++ 程序就不一样了,如下图通过红色方框的内容,确实可以看出有名字修饰,但是其规则比较复杂。