阅读本篇文章你将学到什么?
-
了解什么是默认参数
-
什么是函数重载?
-
为什么C++支持函数重载
-
Gcc编译器下的函数修饰
默认参数的概念
最近我申请了大学英语四的免考,然后询问了学校关于申请免考的机制。我所在学校的免考机制是这样的:假如你申请了我们学校的免考,如果最后你选择不参加考试,那么默认给你75分,而如果你参加考试则按照你自己考试的分数来登记成绩。
这样的机制让我不免想起了最近学习的C++的一个基础概念:默认参数
默认参数、有些地方习惯称为“缺省参数”。
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
void EnglishGrade(int grade = 75)
{
std::cout << "你的英语成绩为:" << grade << std::endl;
}
int main(void)
{
EnglishGrade(); //没有传参时使用默认参数
EnglishGrade(90);//有实参时则使用实参
return 0;
}
运行:
默认参数的分类
缺省参数分为两种:全缺省参数和半缺省参数。
- 全缺省参数
全缺省参数,顾名思义就是,调用函数时没有传实参,参数全部使用默认参数的情况。
同样以我所在学校的机制作为例子,假设有A、B、C三个同学申请了免考:
void EnglishGrade2(int A = 75, int B = 75, int C = 75)
{
std::cout << "A同学的英语成绩为:" << A << std::endl;
std::cout << "B同学的英语成绩为:" << B << std::endl;
std::cout << "C同学的英语成绩为:" << C << std::endl;
}
int main(void)
{
EnglishGrade2(); //全缺省状态下,全部采用默认参数
return 0;
}
- 半缺省
千万不要被这个名字所迷惑,并不是缺省一半的意思,指的是调用函数时传了部分实参,而另一部分采用默认参数。
同样以我所在学校的机制作为例子,假设有A、B、C三个同学申请了免考,但是A同学和B同学偷偷去参加了考试并且分别得到了85,90分的成绩。
void EnglishGrade2(int A = 75, int B = 75, int C = 75)
{
std::cout << "A同学的英语成绩为:" << A << std::endl;
std::cout << "B同学的英语成绩为:" << B << std::endl;
std::cout << "C同学的英语成绩为:" << C << std::endl;
}
int main(void)
{
EnglishGrade2(85, 90); //半缺省状态下,传实参部分使用实参,其余使用指定默认参数
return 0;
}
【注意】
[ 1. ] 缺省参数不能在声明和定义当中同时出现;
[ 2. ]半缺省参数,要求顺序必须是从右到左开始使用默认参数。
[ 3. ]缺省值必须是常量或者全局变量
函数重载的概念
C++允许同一作用域中存在多个同名的函数,尽管函数名相同,但是这些函数的参数列表不同,这种特性被称为函数的重载。
参数列表不同可以是:
- 参数个数不同
- 参数类型不同
- 参数顺序不同
例如:
//函数一
void Add(int x1, int x2)
{
std::cout << (x1 + x2) << std::endl;
}
//函数二
void Add(double x3, double x4)
{
std::cout << (x3 + x4) << std::endl;
}
int main(void)
{
int a = 1, b = 2;
double c = 3.1, d = 4.2;
Add(a, b);
Add(c, d);
return 0;
}
上述例子中函数一与函数二构成了函数重载,它们符合函数名相同,但是参数列表不同。
符号修饰
为什么C不支持函数重载,而C++支持函数重载呢?
这里不得不提到一个重要的概念:符号修饰。
首先我们了解一下函数签名,函数签名包含了一个函数的各种信息,包括函数名、参数类型、所在的类、命名空间及其他信息。
C++编译器和链接器都是使用符号来识别和处理函数及变量的。在编译器和链接器处理符号时,会使用某种名称修饰的方法,使得每一个函数签名都对应一个修饰后的名称,C++的源代码编译后所产生的目标文件中所使用的符号名是修饰后的名称。所以即使函数名相同,编译器和链接器都会认为它们是不同的函数。
Gcc编译器下的基本名称修饰:
- “_Z” + 函数名字的字符串长度 + 每个参数的参数类型的第一个字母
对于嵌套在命名空间或者类里的函数
- “_Z” + 命名空间 / 类的名字字符串长度 + 命名空间/类 + 函数名字的字符串长度 + 函数名 + “E” + 每个参数的参数类型的第一个字母
例如:
而C之所以不支持函数重载就是因为名称修饰的规则不一样。