栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++入门级——函数重载

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++入门级——函数重载

目录

一. 概念

二. 名字修饰

三.extern "C"

1. C++程序调用静态库里的C语言程序

2. C语言程序调用静态库里的C++程序


一. 概念

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数或参数类型或参数类型的顺序)必须不同,常用来处理实现功能类似数据类型不同的问题

int Add(int left, int right)
{
    return left+right;
}
double Add(double left, double right)
{
     return left+right;
}
long Add(long left, long right)
{
     return left+right;
}
int main()
{
     Add(10, 20);
     Add(10.0, 20.0);
     Add(10L, 20L);
 
     return 0;
}

与返回类型无关,以下这个代码就是典型的不是函数重载!

short Add(short left, short right)
{
     return left+right;
}
int Add(short left, short right)
{
     return left+right;
}

二. 名字修饰

首先要知道:在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。

这里需要知道编译链接的具体过程每个过程做的处理,(建议复习一下再继续往下)这里的具体内容在预处理的那篇博客C语言程序环境与预处理

首先来看C语言程序中如果有函数重载会怎么样(为了更好理解在Linux系统下操作)

 使用以下命名行,进行编译查看结果:

(gcc是C语言编译器,-o是编译指令,tc是编译通过后生成的文件名,test.c和f.c是被编译的两个文件)

gcc -o tc test.c f.c

这里发现,编译报错,不通过,说明C语言并不支持函数重载 !

解下来看看C++程序中的函数重载:

 以上文件内容是一致的,但是除了头文件的后缀一致以外,其他两个文件后缀不一致,C语言文件后缀是.c,C++文件后缀是.cpp

 使用以下命令行进行编译:

(g++是C++编译器,-o是编译指令,tcpp是编译通过以后生成的文件名,test.cpp和f.cpp是需要编译的C++文件)

g++ -o tcpp test.cpp f.cpp

以下是编译结果:

没有报错说明编译通过了!C++支持函数函数重载,并在改目录文件下生成了tcpp文件 

 通过以下指令,运行该文件,发现可以运行

./tcpp

通过以上程序知道了C++是支持函数重载而C语言不支持函数重载,那么,接下来是两个个很重要的问题!

为什么C++支持函数重载,而C语言不支持函数重载呢?C++又是如何支持的?

我们的项目通常是由多个头文件和多个源文件构成,当test.cpp中调用了f.cpp中定义的f函数时,编译后链接前,test.o的目标文件中没有f的函数地址,因为f是在f.cpp中定义的,所以f的地址在f.o中,但是test.o里有f的声明和调用,所以test.o里的f函数也有自己的地址,但是两者的地址并不一样(无论是编译还是汇编都是一个文件单独进行的)。链接阶段就是专门处理这种问题,链接器看到test.o调用f,但是test.o的符号表里没有f的地址(指的是定义里f函数的地址),就会到f.o的符号表中找f的地址,然后链接到一起。

编译时,C语言中没有对函数名进行处理,两个函数名相同,而符号汇总以后会生成符号表,在符号汇总时两个函数名一致,此时形成符号表是会出现冲突的,编译器报错。所以,由此可以猜想,在C++中支持函数重载的原因是对函数名进行了处理。

虽然没直接查看符号表但是可以通过以下指令在Linux系统上查看指令集

以下是查看C++的指令集:

objdump -S tcpp

使用该指令以后,找到两个函数的指令集:

 会发现,两个函数的函数名果然不一致,在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。

以下是查看C语言的指令集:

objdump -S tc

指令集的结果如下:

 会发现函数名和我们输入的函数名一致,没有改变,说明在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。

 这就证明了,在C语言中,编译前并不会对函数名进行处理,导致了C语言并不支持函数重载,而C++对函数名进行了处理,支持函数重载

由此也能看出:g++编译的函数修饰后变成【_Z+函数名长度+函数名+类型首字母】

(每个编译器都有自己的函数名修饰规则)

如果想知道windows下对函数名的修饰,参考如下图:

可以看得出来非常复杂,想知道更多的C/C++函数调用约定和名字修饰规则:

C++的函数重载

C/C++ 函数调用约定

所以,我们就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区 分,只要参数不同,修饰出来的名字就不一样,就支持了重载。

 值得一提的是:也从这里知道了为什么函数重载要求参数不同!而跟返回值没关系。

三.extern "C"

有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告诉编译器,将该函数按照C语言规则来编译。

首先看这个程序:

其中的f是C++实现的,并且导入到当前这个C语言程序中,运行以后报错

int f(int t1, int t2);
int main()
{
     f(1,2);
     return 0;
}

链接时报错:error LNK2019: 无法解析的外部符号_Add,该符号在函数 _main 中被引用

我们知道,C语言程序调用C语言程序的库,C++程序调用C++的库是没问题的,那么C语言程序掉i用C++语言的库,C++程序调用C语言的库可以吗?可能会想到他们函数名的修饰都不一样,应该不能调用吧,事实上,是可以调用的。

首先就是C++调用C语言程序是比较简单的,有extern "C",在上述程序中加入这个以后,就不会报错了

extern "C" int f(int t1, int t2);
int main()
{
     f(1,2);
     return 0;
}
  • 静态库的封装

为了更方便查看两者之间的调用关系,先将一个项目封装成静态库,配置方法如下:

 最后应用和确定,这就将一个项目配置成静态库

  • 导入静态库

以下是使用静态库的方法:

 

 

 

 注意:后缀也需要

 添加以后的结果如下:

最后点击应用和确定就配置好了 

  • C语言程序和C++程序的交叉调用

1. C++程序调用静态库里的C语言程序

以上操作做完后,此时运行程序,就会出现以下情况:
这是因为,虽然我们有了函数的声明,但是我们静态库里的程序是C语言程序,而我们引用的头文件是以C++的语法进行编译,我们现在使用的是C++的程序,由于声明是C++里的符号表,而定义却是C语言的符号表,根据上面函数的重载可知两者函数的名是不一样的,所以编译器去符号表里找不到,就导致链接错误

但是由于C++兼容C,所以只要在引用头文件的地方加上extern "C" 就行了,可以让头文件的编译的方式以C语言的方式编译,那声明的符号表里的函数名就和定义的符号表的函数就一致了,这样链接就通过了

(这里需要括号的原因是头文件编译后会展开头文件里的东西,一般会有很多行,我们是要头文件里的东西都以C语言的语法编译)

 这是处理当C++的程序要调用C语言的程序的方法

2. C语言程序调用静态库里的C++程序

那么,如果我们要处理C语言调用C++程序怎么办?

这里先按上面的步骤创建再创建一个C++程序的静态库

然后让C语言程序调用C++的静态库,就会出现以下问题

因为我们虽然引用了头文件,但是是以C语言的语法进行编译,而库里的程序是C++的程序,和上面一样,声明和定义的符号表里的函数名不一致,C语言没有进行修饰而C++的函数进行了修饰,导致符号表合并时找不到函数的定义,就出现链接时错误

这个时候之前学的条件编译就派上用场了,可以在以下链接进行复习

C语言之程序环境和预处理

(之前C++程序调用C语言程序在C++程序上动手,这次C++程序调用C语言程序一样在C++程序动手)

对C++的头文件进行修改:

或者采用下面这种也行,但是更推荐上面那种,更方便

 如上图,我们使用条件编译,让extern "C" 在C++的程序中得到编译,而C语言程序中不被编译,这样在定义的静态库文件里通过extern "C" 让C++程序以C语言语法编译,而在C语言程序里则不出现extern "C" ,并且C语言还是以C语言的语法编译

(extern "C"关键字是C++里特有的语法,C语言没有,extern "C" 能让C++程序以C语言的语法编译,如果该代码在C语言程序中出现则会报错;__cplusplus关键字是C++语法里特有的,在这里是告诉编译器在C++的程序中编译该条件里的代码,否则不执行该代码)

注意一个非常重要的问题,如果C语言程序想要调用C++的程序,C++的程序里不能出现函数重载,因为无论是C++程序的定义还是C语言的调用,都采用的C语言语法编译的,而C语言不支持函数重载

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/867075.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号