什么是函数重载?
函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。
看下面的一个例子,来体会一下:实现一个打印函数,既可以打印int型、也可以打印字符串型。在C++中,我们可以这样做:
void print(int i) { cout<<i<<endl; } void print(string str) { cout<<str<<endl; } int main() { print(10); print("hello !"); return 0; }
通过上面代码的实现,可以根据具体的print()的参数去调用print(int)还是print(string)。上面print(10)会去调用print(int),print("hello ! ")会去调用print(string),如下面的结果:(先用g++ test.c编译,然后执行)
C++是如何实现重载的?
为了了解编译器是如何处理这些重载函数的,我们反编译下上面我们生成的执行文件,看下汇编代码(全文都是在Linux下面做的实验)。我们执行命令objdump -d a.out >log.txt反汇编并将结果重定向到log.txt文件中,然后分析log.txt文件。
发现函数void print(int i) 编译之后为:(注意它的函数签名变为——_Z5printi)
发现函数void print(string str) 编译之后为:(注意它的函数签名变为——_Z5printSs)
我们可以发现编译之后,重载函数的名字变了不再都是print!这样不存在命名冲突的问题了,但又有新的问题了——变名机制是怎样的,即如何将一个重载函数的签名映射到一个新的标识?我的第一反应是:函数名+参数列表,因为函数重载取决于参数的类型、个数,而跟返回类型无关。但看下面的映射关系:
void print(int i) --> _Z5printi
void print(string str) --> _Z5printSs
进一步猜想,前面的Z5表示返回值类型,print函数名,i表示整型int,Ss表示字符串string,即映射为返回类型+函数名+参数列表。最后在main函数中就是通过_Z5printi、_Z5printSs来调用对应的函数的:
80489bc: e8 73 ff ff ff call 8048934 <_Z5printi>
……………
80489f0: e8 7a ff ff ff call 804896f <_Z5printSs>