01-函数重载(Overload)

我们知道,在C语言当中,是不支持函数重载的,但是C++支持函数重载,并且有很多语言都支持函数重载。

例如下列的两个函数,函数名相同,参数的个数不同,就构成了函数的重载

int sum(int v1, int v2) {
    return v1 + v2;
}

int sum(int v1, int v2, int v3) {
    return v1 + v2 + v3;
}

当参数个数不同,但是参数的类型不同时,也可以构成重载。例如

void func(int v1, double v2) {
}

void func(double v1, int v2) {

}

函数重载的规则

  1. 函数名相同
  2. 参数的个数不同
  3. 参数的类型不同
  4. 参数的顺序不同

注意以下情况,不能构成函数重载

1.返回值类型与函数重载无关,例如下列的两个函数

void func(int v1, double v2) {
}

double func(int v1, double v2) {
    return 0;
}

上面的两个函数,不构成函数的重载,在编译器中,会直接标错[下图],代码不能通过。

我们想想为什么这种情况下不能构成重载?

因为这样会有歧义,有二义性。加入上面两个函数可以构成函数重载,那么我们通过下列方法调用函数时,最终应该调用哪个方法呢?

int main() {
    func(10, 10.5);
    getchar();
    return 0;
}

难道不觉得调用这两个函数都合理吗?这样就导致有歧义,不能构成重载、

2.调用函数时,实参的隐式类型转换可能会产生二义性,例如下列的三个函数

void display(long a) {
    cout << "display(long) -" << a << endl;
}

void display(double a) {
    cout << "display(double) -" << a << endl;
}

void display(int a) {
    cout << "display(int) -" << a << endl;
}

如果我们通过这种方式来进行调用的话,是可以分别调用成功的

int main() {

    display(10);
    display(10L);
    display(10.0);
    
    getchar();
    return 0;
}

但是,当我们去掉函数void display(int a)以后,会发现我们程序就报错了。

因为此时编译器发现,display(10)调用函数void display(long a)合理,调用函数void display(double a)也是合理的。因为这个时候调用display(10)时,传入的参数存在隐式转换。因为我们平时就可以将一个int类型赋值给一个long类型,也可以将一个int类型赋值给一个double类型,例如这样去写代码

long l = 10;
double d = 10;

上面这种写法,其实是有一个转换操作,编译器自动将int类型转为了long/double类型。因此当我们去掉函数void display(int a)以后,通过display(10)调用两个函数都是合理的,因此又产生了二义性,所以编译器会给出错误的提示,所以这种情况也不构成函数的重载。

函数重载的本质

为什么C++支持函数重载,而C语言不支持函数重载呢?本质是采用了name mangling或者叫name decoration技术

C++编译器默认会对符号名(比如函数名)进行改编,修饰;有些地方翻译为“命名倾轧”

同样的假设我们有以下三个函数

void display(long a) {
    cout << "display(long) -" << a << endl;
}

void display(double a) {
    cout << "display(double) -" << a << endl;
}

void display(int a) {
    cout << "display(int) -" << a << endl;
}

编译器会对这三个函数重载的函数进行name mangling的操作。我们从表面上看函数名叫做display,但是编译器会分别对函数名进行改编修饰。例如函数void display(int a)在真正编译的时候,函数名可能变为了display_int,函数void display(long a)在真正编译的时候,函数名可能变为了display_long,函数void display(double a)在真正编译的时候,函数名可能变为了display_double,改编后的会变为一个新的函数名,而这个新的函数名,会包含参数信息。这样的话,就能保证三个函数,可以共同存在。

但是,在不同的编译器(MSVC,g++)有不同的生成规则,因此最终函数会被改编成什么样,是根据编译器的规则来进行的。

证明函数重载的本质

我们可以利用反汇编,来看一下构成函数重载的函数,在运行是,最终转成的汇编代码

我们新增一个无参的函数以后,在main函数中调用该函数,并且在调用哈数的地方打上一个断点,然后将程序运行起来。

void display(long a) {
    cout << "display(long) -" << a << endl;
}

void display(double a) {
    cout << "display(double) -" << a << endl;
}

void display(int a) {
    cout << "display(int) -" << a << endl;
}

void display() {
    cout << "display() -"<< endl;
}

运行起来以后,在编译器代码区右击鼠标,选择转到反汇编,我们就可以来到当前代码转为的汇编代码

首先我们知道,每一条汇编指令都有自己对应的内存地址,并且是按顺序往下执行的,并且连续的汇编指令,对应的地址也是连续的。

我们从上图中看到,对应在代码中的函数调用,转到汇编以后,call指令调用的函数名也是一样的。这和我们预想的结果有点不一样。但是有一点不一样,就是在call指令调用display时,括号内的东西不一样,那这里面的东西是什么呢?这其实是调用对应函数的内存地址,因此我们发现,在调用函数时,虽然看到call指令调用的函数名好像都是display,但是调用的地址却不一样,因此我们推断,调用的函数并不是同一个函数。

因此我们可以借助一个工具 IDA Pro来查看我们代码打包成可执行文件后的反汇编代码。并且将我们C++编译器的模式设置为Release模式,再关闭编译器的优化功能。

最终反编译后,我们看到main函数是这样的

并且我们看到左边有4个不同的display函数名,我们可以看一下这4个函数的具体实现,最终我们发现

所以我们看到,最终的函数名是不一样的

而且,我们还发现,函数名称的生成顺序和我们函数定义的顺序是一样的。

因此,我们证明了上面说的,C++函数重载,使用了name mangling技术。

demo下载地址

文章完。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容