C++是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度抽象和建模时,C语言则不合适。为了解决软件危急,20世纪80年代,计算机界提出了OOP(面向对象)思想,支持面向对象的程序设计语言应运而生。
本篇将为大家介绍C++的基础语法,由于C++向下兼容C语言的大多数语言特性,对于一些C语言已具备的语法,将不做论述
前文索引:
C++入门篇——深入C++基础语法(一)
目录
三、缺省参数
缺省参数的概念
缺省参数的分类
四、函数重载
函数重载的概念
名字修饰
缺省参数是在函数声明或定义时,为函数的参数设置一个默认值。
在调用这个函数时,如果使用者没有对其特定参数进行传参,则该参数将采用其默认值。
如下便是为函数指定了一个缺省参数:
void func(int a = 1)
{
cout << a << endl;
}
我们不对其进行传参,直接调用,就会输出默认值:
int main()
{
func();
return 0;
}
所谓全缺省参数,即为所有的参数设置了缺省值:
void func(int a = 1, int b = 2, int c = 3)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
在调用函数时,可以不传任何参数,此时所有参数都使用指定的实参。
当然,也可以部分传参,但必须满足“不能跳跃传参的原则”,即传过去的参数必须是从左向右连续的。
针对上述函数,有以下4种传参方式:
int main()
{
func();
cout << endl;
func(0);
cout << endl;
func(0,0);
cout << endl;
func(0,0,0);
cout << endl;
return 0;
}
输出结果如下:
半缺省参数,即缺省部分参数,正确设置半缺省参数有两个原则:
1、必须从右向左缺省
2、必须连续缺省
因此如果想将上面的函数转化为半缺省,只有两种情况,即:
void func(int a, int b = 2, int c = 3)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
void func(int a, int b, int c = 3)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
同时,缺省参数不能在函数声明和定义中同时出现,否则编译器不能够确定采取哪个缺省值。
在同一作用域中,C++允许同时声明几个功能类似的同名函数,这样的函数即为重载函数。
要构成重载函数,它们的形参列表(参数个数或类型或顺序)必须不同,常用来处理实现类似而数据不同的问题。
以下函数互为重载函数:
void print(int a)
{
cout << a << endl;
}
void print(float a)
{
cout << a << endl;
}
void print(int a, float b)
{
cout << a << b << endl;
}
void print(float a, int b)
{
cout << a << b << endl;
}
注:只有返回值不同的函数不能构成重载,原因是在调用时编译器无法区分,存在歧义。
那么为什么C++支持函数重载,而C语言不支持呢?或者说C++是如何支持函数重载的呢?要弄清楚这个问题,就要了解一下C++的名字修饰。
在此之前,先梳理一下C/C++中程序运行所要经历的几个阶段:预处理、编译、汇编、链接。
预处理:头文件的展开、宏替换、条件编译、去注释等
编译:检查语法,生成汇编代码
汇编:将汇编代码转换为二进制的机器码
问题的关键就在于链接。
我们先来看看vs2019下C语言的名字修饰规则
int main()
{
func();
return 0;
}
直接运行会报错:
可以看到这里的 _func就是修饰过后的名称。
如果在C语言中写入两个函数名相同的函数,它们的名称都将被修饰为_func,此时在链接时,编译器就不知道该填入哪个函数的地址,因为它们的名字修饰完全相同。
再来看看C++:
int main()
{
func(1);
func(1, 1);
return 0;
}
可见名字的修饰就复杂了许多,两个重载函数的名字修饰各不相同,因此在链接时,编译器可以根据不同的名字修饰,得到对应函数的正确地址。
总结:C++的目标文件符号表不是直接用函数名来表示和查找函数的。
1、函数名修饰规则,不同编译器不同
2、有了函数修饰规则,只要参数不同,符号表里重载的函数就不存在二义性和冲突了,连接查找重载函数的地址时,也是明确的了