C++函数重载
1.函数重载概念
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,但这些同名函数的形参列表(参数个数或类型或顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。
// 形成函数重载的三个函数
int Add(int left, int right)
{
return left + right;
}
double Add(double left, double right)
{
return left + right;
}
long Add(long left, long right)
{
return left + right;
}
int main()
{
Add(10, 20);
Add(10.0, 20.0);
Add(10L, 20L);
return 0;
}
问:下面函数属于函数重载吗?
short Add(short left, short right)
{
return left+right;
}
int Add(short left, short right)
{
return left+right;
}
答:由于函数的形参个数、类型以及顺序完全相同。所以不构成函数重载。
2.名字修饰
为什么C++支持函数重载,而C语言不支持函数重载呢?
2.1.程序编译过程
在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接
2.1.1.程序编译过程
1.预处理阶段
1. 展开头文件
2. 宏替换
3. 去注释
4. 条件编译
2.编译阶段
1. 检查语法错误
2. 生成汇编代码
3.汇编阶段
1. 将汇编代码转换成二进制代码(机器语言)
2. 将指令打包成一种叫做可重定位的目标程序格式
4.链接阶段
1.合并段表
2.合并符号表与符号表的重定位
3.得到可执行文件可以被加载到内存中,由系统执行。
2.1.2.程序编译过程图示
2.2.过程模拟
2.2.1.链接的作用
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函数,链接器会使用哪个函数名字去寻找呢?每个编译器都有自己的函数名修饰规则。
2.2.2.使用Linux进行过程模拟
1.使用vim创建程序
头文件:list.h
#pragma once
#include <stdio.h>
void list_push_back(int x);
源文件:list.c
#include "list.h"
void list_push_back(int x)
{
printf(" %d ", x);
}
测试文件:test.c
#include "list.h"
int main()
{
list_push_back(1);
return 0;
}
2.查看函数名
(1). 使用 gcc 编译器编译,将源代码转化成可执行程序 listc
输入指令:
gcc -o listc list.c test.c list.h
(2). 使用 g++ 编译器编译,将源代码转化成可执行程序 listcpp
输入指令:
g++ -o listcpp list.c test.c list.h
(3).分别输入:
objdump -S listc
与objdump -S listcpp
;
转到反汇编。
可以看到如下函数名:
结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数名字符长度以及参数类型信息添加到修改后的名字中。
2.2.3.Windows下名字修饰规则
对比Linux之后可以看出,windows的c++编译器对函数名字修饰比较诡异,但是基本原理是相同的。
3.结果比较
3.1.C++编译器与C编译器比较
结论:通过上述结果我们就理解了C语言无法支持重载,因为同名函数无法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,所以就支持了重载。
注: 函数重载只要求参数不同!而跟返回值没关系 !!!
3.2.extern “C”
有时候在C++工程中可能需要将某些函数按照C风格来编译,则可以在函数前加 extern “C”。含义是告诉编译器,将该函数按照C语言规则来编译。
比如:tcmalloc是google用C++实现的一个项目,提供tcmallc()和tcfree两个接口来使用,但如果是C项目就没办法使用,那么就使用extern “C”来解决。
代码表示:
extern "C" int Add(int left, int right);
int main()
{
Add(1,2);
return 0;
}
4.面试题
1.下面两个函数能形成函数重载吗?有问题吗或者什么情况下会出问题?
void TestFunc(int a = 10)
{
cout<<"void TestFunc(int)"<<endl;
}
void TestFunc(int a)
{
cout<<"void TestFunc(int)"<<endl;
}
答:虽然两个函数一个为全缺省,一个没有缺省,但是函数名和函数的形参类型、个数、顺序完全相同。所以不形成重载;函数会在链接阶段出问题。
2. C++中能否将一个函数按照C的风格来编译?
答:可以,在函数前加 extern "C"即可。