C札记深入浅出C函数重载

本文阅读目录

1、什么是重载函数

2、函数重载的好处

3、编译器如何解决命名冲突

4、extern"C"作用

什么是函数重载

学过C语言的同学应该很清楚,在C语言中,同一个程序中是不能定义多个名称相同的函数,否则编译会报重定义的错误信息,但是C++中则允许定义多个名称相同的函数,在C++中,这称之为函数重载,让我们来看看更官方一点的定义,函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。此外需要注意的是,函数的返回值不构成重载条件。看下面几组示例。

//类A和类B的两个同名show()函数不构成重载//因为两个函数的作用域不一样classA{public:  voidshow(intx){}  };classB{public:  voidshow(doublex){}  };

//类A两个同名show()函数不构成重载//因为两个函数的参数一样,返回值类型不同不能构成重载classA{public:  voidshow(intx){}    intshow(intx){}};

//类A两个同名show()函数构成重载//因为两个同名函数作用域相同,且参数列表不一样classA{public:  voidshow(intx){}    voidshow(doublex){}};

注:重载函数的条件之一参数列表不同包括参数个数不同或者参数类型不同或者参数顺序不同都可以。

函数重载的好处

先想想下面一个场景,如果一个程序要实现一组加法操作,既要能够处理两个整数,又要处理两个字符串相加,你会如何做了?如果是C语言,你必须为这组函数取不同的名字,如add_int,add_str等等,是不是程序的可读性不太好。如果是C++实现,由于其支持函数重载,因此可以用一个函数名add就OK了,这样就避免了名字空间的污染,提高了程序的可读性。

再想想,如果没有函数重载机制,每个类只能存在一个构造函数(因为构造函数名字必须与类名相同),因此,要想以不同的方式实例化类对象,就会变的相当麻烦。

编译器如何解决命名冲突

我们定义两个重载函数如下图所示,然后对生成的可执行利用objdump-da.out命令进行反汇编观察,可以看出,intadd(intx,inty)编译之后其函数签名变为__Z3addii,函数floatadd(floatx,floaty)编译之后其函数签名变为__Z3addff,不难发现,经过编译之后,函数名变的不那么单纯了,会增加一些其它的信息进去,具体说来,编译之后的函数名会包含返回值类型的信息、参数列表信息等等。这种技术叫命名修饰。

不同编译器的命名修饰规则也不一样,这里就不深究了,我们只要知道C++中是通过这种机制来解决函数重载命名冲突的就好了。

extern"c"{}作用

通过前面分析可知,C++是一个面向对象语言,它支持函数重载,而C语言中并没有函数重载,编译器在编译C++程序和C语言时的机制有些不同,比如说对于同一个函数intadd(intx,inty);其函数名在C++中将被编译为__Z3addii;而在C语言中可能就是直接编译为__add。

因此,如果C++中含有C语言代码时,就可能会出问题。因为在编译时C++编译器对C代码的函数也会进行名字修饰,函数名变了以后,将导致在C运行库中找不到对应函数,发生链接错误。比如说对于以下代码:

//print.cppintprintf(constchar*format,...);intmain(){printf("Helloworld!");return0;}

看看编译时发生了什么:

bogon:lizhong$g++-oprintprint.cppUndefinedsymbolsforarchitecturex86_64:"printf(charconst*,...)",referencedfrom:_maininprint-f04c36.old:symbol(s)notfoundforarchitecturex86_64clang:error:linker


转载请注明:http://www.aierlanlan.com/grrz/456.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了