什么是函数重载?

      函数重载是指在同一作用域内,可以有一组具有相同函数名不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。

看下面的一个例子,来体会一下:实现一个打印函数,既可以打印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>

再有int max(int a,int b) 映射为_Z3maxiidouble max(double a,double b) 映射为_Z3maxdd,这证实了我的猜想,Z后面的数字代码各种返回类型。规则是:“返回类型+函数名+参数列表”。

相关文章: