个人主页:欢迎大家光临——>沙漠下的胡杨
各位大帅哥,大漂亮
如果觉得文章对自己有帮助
可以一键三连支持博主
你的每一分关心都是我坚持的动力
![]()
☄: 本期重点:缺省参数和函数重载
希望大家每天都心情愉悦的学习工作。
目录
概念:
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
特点:
1.缺省参数分为:全缺省和半缺省
2. 半缺省参数必须从右往左依次来给出,不能间隔着给
3. 缺省参数不能在函数声明和定义中同时出现4. 缺省值必须是常量或者全局变量
5. C语言不支持(编译器不支持)
全缺省参数的函数,我们分别不传参数,传一个参数,传看两个参数,传三个参数。
void func(int a = 200,int b =20,int c = 2) { std::cout << a << std::endl; std::cout << b << std::endl; std::cout << c << std::endl << std:: endl; } int main() { func(); func(1); func(1, 10); func(1, 10,100); return 0; }
半缺省参数的函数:
void func(int a,int b = 20 ,int c = 2) { std::cout << a << std::endl; std::cout << b << std::endl; std::cout << c << std::endl << std:: endl; } int main() { func(3); func(3,30); func(3,30,300); return 0; }
在传参数时,必须从左到右来给,不能间隔给,否则报错:
缺省参数不能在定义个声明中同时存在:
主要是防止声明和定义万一给不同的缺省值会出错,一般我们在声明中写,不在定义中写
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
简单来说就是多个函数使用一个名字,其中函数参数的个数和类型不同或者是不同类型参数的顺序不同(返回值不同不构成函数重载)。
根据函数参数的个数,类型,参数的顺序不同,构成函数重载(返回值不同不构成函数重载):
int Add(int a, int b,int c) { return a + b + c; } double Add(double a, double b) { return a + b; } int Add(double a, int b) { return a + b; } double Add(int a, double b) { return a + b; } int main() { std::cout << Add(1, 2, 3) << std::endl; std::cout << Add(1.11, 2.22) << std::endl; std::cout << Add(3, 3.33) << std::endl; std::cout << Add(4.44, 4) << std::endl; return 0; }
那么如果是加上缺省参数,会影响函数重载吗?
只有缺省参数来区分函数参数,是不能够构成函数重载的。
我们在Linux平台下进行演示,首先形成可执行程序时我们要经历四个大的步骤,分别是:预处理,编译,汇编,链接,才形成的我们的可执行程序。
我们要了解具体过程参考文章如下:gcc和g++的编译过程
其中我们在汇编时期我们生成的一个叫做符号表的东西,其中会有函数名,也就是函数第一条指令的地址,我们C语言生成函数名的规则和C++不太一样,C++中我们可以通过函数名的长短和参数类型的首字母来进行区分,才能够实现函数重载。
下面我们先来演示下:
上面只是一个简单的打印函数,我们使用了函数重载,下面我们使用不同的编译器进行编译试试看会发生什么呢?
gcc编译器:我们发现会报错,说是函数名冲突。
g++正常通过,运行结果正常:
此时我们能够证明C++支持函数重载而C语言不支持,那么为什么呢?
我们使用下面的命令可以常看汇编代码,然后我们查看函数名的不同可以区分出来。我们先看下C++的函数名吧:
objdump -d func
我们是可以看出C++的函数名是修饰过的,比如函数名后面就是类型的首字母。
我们再来看看C语言的,为了保证代码编译通过,我们把函数名设置为不同。
我们先把代码修改过之后,然后我们重新编译通过了,接着我们进行了查看汇编的函数名,发现我们C语言没有所以的函数名之后有参数的类型之分,所以不能支持函数重载。
总结:我们C++支持函数重载是因为函数名修饰规则,我们在汇编阶段形成的符号表中如果有相同的函数名那么我们的C++是可以进行识别的,而我们的C语言在两个函数名相同的情况下,我们没有函数名修饰规则,不能够区分两个相同的函数名。
为什么有extern “C”?
由于C和C++编译器对函数名字修饰规则的不同,在有些场景下可能就会出问题,比如:
1. C++中调用C语言实现的静态库或者动态库,反之亦然
2. 多人协同开发时,有些人擅长用C语言,有些人擅长用C++在这种混合模式下开发,由于C和C++编译器对函数名字修饰规则不同,可能就会导致链接失败,在该种场景下,就需要使用extern "C"。
extern “C”是什么?
在函数前加extern "C",意思是告诉编译器,将该函数按照C语言规则来编译。
下面我们在VS下使用这个extern “C”,我们分别形成一个C语言的静态库,让C++进行调用,在形成一个C++的静态库,让C语言来进行调用。
关于动静态库的概念参考文章:动态链接和静态链接
C++程序调用C语言形成的静态库:
我们使用20. 有效的括号 LeetCode这道题目进行演示。我们先创建一个C的静态库,库中包含我们的栈的实现和声明。然后我们使用C++程序编写这道题目,其中我们不在C++程序中再写 栈的实现,我们要使用静态库进行链接。达到一个程序只负责使用函数的接口,剩下的函数实现的全部由静态库实现。
到这里我们就完成了C语言静态库的生成,下面我们编写C++程序让他来调用这个静态库即可。下面是主函数的部分和一个函数。在函数中我们使用了栈的一些函数接口,我们要是用静态库的方式把函数的实现和函数的接口链接起来,进而完成程序。
我们先包含头文件。我们采用相对路径的方式包含。
![]()
其中 .. 表示返回上级目录 其中 / 表示我们在这个目录下。
接着我们还要修改链接器:
![]()
最后我们会发现还是链接错误,为什么呢?
因为我们的静态库是C语言编译器生成的,但是我们的程序是C++的,在链接阶段会出现符号表不相同,其中的函数名修饰规则等等不一样,所以我们链接不上,怎么解决呢?我们要在编译阶段就要告诉我们C++的程序,要按照C语言的标准来进行编译头文件等等.. 这时我们就要使用extern “C”了。我们在头文件上包含extern “C”就可以解决啦。最后我们还要先清理解决方案,然后在重新生成就可以运行啦。
C程序调用C++的静态库:
同样的我们还是要生成静态库,此时我们生成的是C++的静态库。但是我们最后要让C语言进行调用的,所以我们即要形成C++的静态库,又要让C语言进行识别,我们要采用条件编译,如果是C++的程序那么就使用即可,如果是C语言的程序,那么我们在预处理时就要知道我们要安装C语言的规则来进行编译。我们对函数的声明进行extern “C”,就可以做到。
![]()
最后我们让C语言进行调用即可。
总结来说:其中C++编译器是可以区分C语言和C++的不同规则,原因是因为C++要兼容C语言,但是C语言编译器不知道C++的一些规则,所以我们一般要让C++调用C的库,或者C调用C++的库,都是要改动C++的东西才行,因为C语言不认识这个extern “C”。
今天就到这结束啦!