C++名字修饰以及函数重载

C++函数重载

------引言

想起某一年小品,沈腾出演,其中,较为经典的两句台词,也是比较符合函数重载概念的,今天我就拎出来给大家说说。

  • 打败你的不是天真,是无鞋(无邪)
    这句话在小品中,含义首先是,郝建鞋子掉了,所以说的是无鞋,另一种意思是无邪,在合适的时机,用到合适的场合。
  • 要梨不—离!离就离!
    这句话也能体现出,一个相同的发音,却有着不同的意思,在不一样的场合下,对于相同发音的词,对于不同的人,也有着不同的动作以及回应。
    这就是今天所要分享的:在C++层面上的函数重载

函数重载

概念

When two or more different declarations are specified for a single name in the same scope, that name is said to overloaded. By extension, two declarations in the same scope that declare the same name but with different types are called overloaded declarations. Only function declarations can be overloaded; object and type declarations cannot be overloaded.
——摘自《ANSI C++ Standard. P290》

首先来讲一下函数重载的概念:函数重载是函数的一种特殊状况,C++允许在一个作用域中声明多个相同名称的函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,返回值类型不同不能作为函数重载标准
常用来处理功能类似但是数据类型不同的问题。

代码书写格式
int add(int left , int right)
{
	return left + right;
}

//参数类型不同
double add(double left, double right)
{
	return left + right;
}

//参数格式不同
int add(int left, int mid, int right)
{
	left += mid;
	return left + right;
}

//返回值类型不同不能作为函数重载的参照
double add(int left, int right)//error
{
	return left + right;
}
int main()
{
	return 0;
}

大家可能要问,C++中是怎样实现相同名称的函数重载的呢,为什么C语言就不可以,到底是C++改进了哪些内容从而可以将函数重载实现了。
名字修饰规则告诉你答案

名字修饰

作者使用的编译器为VS2013、win32位平台,debug模式在不同编译器下,可能会不大一样,但是也不会相差很大
在C/C++中每个代码要运行,必不可少的四道过程预处理、编译、汇编、链接(本篇博客不对其进行深究)在编译过程中,编译器会将函数、变量的名字进行改编,从而可以使编译器能够较为容易看懂。

先来看一下C语言下的名字修饰
  • 在C语言中如果对于一个函数定义有问题,或者没有定义,运行时会报出如下的错误:
    代码是这样的:?
//没有add函数的实现,并且在main函数中调用add函数
int add(int left, int right);//只有声明

int main()
{
	add(1, 2);
	add(1.1, 2.2);
	return 0;
}

报错是这样的?

nameMangling.obj : error LNK2019: 无法解析的外部符号 _add,该符号在函数 _main 中被引用

这个错误是C语言编译器编译之后对于函数的修饰名字出现了更改,在C语言中,只是简单的将名字前加了一个下划线,所以如果想要完成重载,那么就一定需要将重载函数的定义让编译器识别的出来,但是遗憾的是在C语言中,并没有将该功能实现,所以在C语言中没能完成的事情,就交给C++吧!

再来看一下C++中的名字修饰
  • C++中的报错完全不一样了,而且, 比C语言上的报错要难以理解好多倍。
    实例代码是这样的?
//同样只给声明,没有给出实现
int add(int left, int right); 
double add(double left, double right);

int main()
{
	add(1, 2);
	add(1.1, 2.2);
	return 0;
}

报出的错误是这样的?

error LNK2019: 无法解析的外部符号 "int __cdecl add(int,int)" (?add@@YAHHH@Z),该符号在函数 _main 中被引用
day_1.obj 
error LNK2019: 无法解析的外部符号 "double __cdecl add(double,double)" (?add@@YANNN@Z),该符号在函数 _main 中被引用
F:\代码\C++\C++-review\Debug\C++-review.exe : fatal error LNK1120: 2 个无法解析的外部命令

这个错误是C++编译器编译之后对于函数的修饰名字可以看出来与C语言中出现了奇怪的命名方式不过不要紧,咱们慢慢来,仔细观察这名字的特点。细心的朋友已经发现相同函数名称的函数在编译器进行编译之后在内部名字是不同的,这一点就已经证明了C++中允许了函数的重载。

接下来,咱们来看看这个奇怪的名字具体都是一些什么含义
先来看一下一般的名字修饰
double add(double, double);
(?add@@YANNN@Z)
int add(int, int);
(?add@@YAHHH@Z)
double add(double, int);
(?add@@YANNH@Z)
  • ?:修饰后的名字有" ? "打头,标识函数名字的开头
  • add:显然为该函数的(用户可以看懂的部分函数名称)不同的函数函数名称也是不同,但相同函数修饰后函数名称相同
  • @:由@符号结尾函数名add
  • @@:暂且先认为这两个符号表示分隔符,并且两个@@之间可以放置作用域标识
  • YA:标识函数调用类型(函数调用约定)常见的函数调用类型有(cdecl,stdcall,fastcall,thiscall,nakedcall)此处不做详细探究。
  • NNH:表示函数的调用返回值类型以及参数类型,在机器内部有机器自身的编码方式
  • @Z:由@表示结束,由Z表示结尾
下面是一些复杂的名字修饰
int C::Func(int);
(?Func@C@@AAEHH@Z)
int N::C::Func(int);
(?Func@C@N@@AAEHH@Z)
  • 在这两个函数声明中,可以更好的理解了@@的作用是什么了:@C@N表示了用@符号把命名空间进行分隔,再使用一个@表示命名空间结束。(对命名空间不够了解的朋友可以看笔者之前博客,有略微的讲解)
    这也印证了为什么C++可以实现函数重载,我们可以看到函数名、参数类型、返回值类型和命名空间都被加入了修饰后,这样编译器和连接器就可以区别对点同名但是不同参数或者不同命名空间下的函数,而不会导致link时出现函数重定义
    也可以观察一下其他C++编译器对于名字修饰的做法,在此笔者不做探讨。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值