【C++02】C++中函数重载问题

函数重载:

函数重载是C++在C语言的基础上新增的功能,它指的是在同一作用域内,一组函数的函数名相同,参数列表不同(个数不同/类型不同/顺序不同),返回值可同可不同。它对函数名称进行了重载,函数重载让你能够使用多个同名的函数(可以通过函数重载来设计一系列的函数——它们完成相同的工作,但使用不同的参数列表)。

函数特征标:

函数重载的关键是函数的参数列表(函数特征标),C++允许定义名称相同的函数,条件是它们的特征标不同,即要求参数数目不同/参数类型不同/参数顺序不同,参变量名和返回值类型是无关紧要的。我们可以定义原形如下的Show函数:


这里需要注意的是编译器在检查函数特征标时把类型引用和类型本身视为同一个特征标,你可能会认为此处可以使用函数重载,因为它们的特征标看起来不同。请看下面两个原型:


假设当你使用语句 std::cout<<cube(d)<<std::endl; 来调用此函数时实参d与double d和double& d都匹配,因此编译器无法识别此处应使用哪个函数原型。

何时使用函数重载:

仅当函数基本上执行相同的任务,但使用不同形式的数据时,才采用函数重载。因为你用函数重载实现的一系列函数功能不同时程序的可读性很差,免不了还有一定的误导。

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

C语言不支持函数重载,C++是支持的。这里我们从程序的编译到链接来理解这里的问题(简单说一下程序的执行)。组成一个程序的多个源文件通过编译过程分别(独立完成)转换为目标代码,这是编译阶段完成的。然后通过连接器将这些目标文件与标准C函数库中当前程序所用到的函数(也可以引进程序员自己的程序库)链接起来形成单一而完整的可执行程序,这是链接的过程完成的。下图描述了这个过程:


编译阶段

编译阶段本身又可分为预编译(也叫预处理和预处理器处理)、编译、汇编三个子阶段,这里通过一个完整的C程序理解这个过程。代码如下:


预编译阶段:

头文件的展开

去除注释

#define定义的标识符的替换

宏的替换(宏一定是带参数的

编译阶段:

语法分析

词法分析

语义分析(有时候编译器在不要改变局部程序功能的前提下,对其进行优化处理

符号汇总

汇编阶段:

形成符号表(当有全局变量时,符号表中不只是有函数也有全局变量


在main.c中编译器给_sum.c的地址(0x000)是虚拟的,由于整个编译阶段对两个文件的操作是独立的,所以在申明时无法给出真实地址。

链接阶段

链接阶段将多个目标文件与库函数单一而完整的链接在一起形成可执行文件。

合并段表

符号标的合并与重定位(将多个文件的符号表进行合并,全局变量和函数统一用定义时编译器分配的地址,抛弃申明阶段给的虚拟地址


说到这里我们可以回答起初的问题了。C语言中编译器对函数名的处理只是在函数名前加下划线(_sum/_main),在这一块的处理中不考虑参数,而在C++中参数类型/参数数目/参数类型顺序都是编译器处理时引进的元素(_sum_int_int)。所以在C++中只要函数的特征标不同,经过编译器处理那些同名的函数在符号表中的表现出的形式是不同的,符号表合并时不会仅仅因函数名相同而使编译器无法处理。你也发现了这一块的处理中没有提到函数返回值和函数的参变量,这也真是函数重载中函数的返回值和参变量无关紧要的原因。

执行阶段

首先程序必须载入到内存中。在具有操作系统的环境中,这个任务由操作系统来完成;在独立环境中,程序的载入必须由手工安排,也可能是通过把可执行代码置入只读内存来完成。那些不是存储在堆栈中尚未初始化的变量将在这个时候得到初始值(程序执行的最后一个阶段是程序的终止)。

猜你喜欢

转载自blog.csdn.net/Work_Hard_Zxm/article/details/80720269
今日推荐