C++是在C语言的基础上发展而来的,解决了C语言中存在的一些明显的问题。本文针对C语言存在的问题,引出C++中的解决方案,以对C++的语法进行说明和分析。
命名空间
域的概念
可以将C++中的域理解为作用域。C++标准规定:使得特定名字保持有效的那些可能并不连续的程序文本就是该名字的作用域。作用域限定了名字的可见范围和使用范围。C++中常见的域有:类域、命名空间域、局部域、全局域。
什么是命名空间
在大型的计算机程序或文档中,往往会出现数百或数千个标识符,若使用C语言完成这些程序,往往会造成命名冲突的问题,命名冲突主要体现在两点:1.与库中的标识符冲突 2.与其他协作组成员的标识符冲突。解决这一问题是命名空间存在的主要理由。
在C++中,将声明与定义组合到一个声明区域,称为命名空间。当使用namespace
关键字定义一个命名空间域时,该域可对域中的变量/函数/类型进行隔离。一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。关于命名空间,有如下几点需要注意:
- 命名空间不以分号( ; )结尾定义;
- 命名空间往往是是用来限制全局声明/定义的;
- 命名空间可以嵌套定义;
- std为C++标准库的命名空间;
- (同一项目的不同文件中)多个相同的命名空间域会被视为同一个命名空间域
namespace shr
{
//命名空间的嵌套定义
namespace shr_A
{
int a = 10;
int b = 20;
}
namespace shr_B
{
int c = 13;
int d = -21;
}
}
//与上面的命名空间一起会被视为同一个命名空间
namespace shr
{
int n; //默认为 0
int sum(int x, int y)
{
return x + y;
}
}
命名空间的使用
若要使用命名空间中的声明/定义,有如下三种方式
- 将命名空间全部展开
- 使用域作用限定符(
::
)对命名空间中的某个成员进行指定访问 - 使用
using
将命名空间中的某个成员引入
namespace shr
{
int n; //默认为 0
int sum(int x, int y)
{
return x + y;
}
}
//全部展开
using namespace shr;
//指定引入
using shr::sum;
int main()
{
//指定访问
int sum = shr::sum(2, 7);
cout << "sum = " << sum << endl;
return 0;
}
编译器的搜索顺序为:局部域->全局域->被展开或者被指定了的命名空间域。命名空间不展开/不指定时不去命名空间域进行搜索。使用命名空间时,需要注意下面几点:
- 展开命名空间相当于把域中所有的声明/定义暴露到上一级空间;
- 不建议将命名空间直接全部展开,建议使用
using
将所需的指定成员引入
缺省函数
什么是缺省函数
缺省函数的参数列表中含有缺省参数。缺省参数在声明或定义函数时为函数的参数指定一个缺省值,在调用函数时,如果没有实参则形参采用形参的缺省值,否则使用指定的实参。
缺省函数分类
缺省函数按照函数参数列表中缺省参数的数量,分为全缺省函数和半缺省函数。全缺省函数的参数列表全部为缺省参数,半缺省函数的参数列表部分、依次缺省。
//全缺省函数
void Func(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
//半缺省函数,缺省参数从右往左依次给出
void Func(int a, int b = 10, int c = 20)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
const int default_capa = 10;
//缺省参数的值必须为常量或者全局变量
int* CreatArr(int n = default_capa)
{
int* ret = (int*)malloc(sizeof(int) * n);
return ret;
}
缺省函数的使用使模块化程序设计更加灵活,开发者可以根据自己的需要进行指定传参或直接使用参数的默认值。定义和使用缺省函数时需要注意以下几点:
- 为了避免函数传参的歧义,有多个缺省参数时,实参默认从左向右传递;
- 不能对某一个缺省参数进行指定传参;
- 函数的声明和定义不能同时缺省,只需要在函数的声明中缺省(若有)。这样做是考虑到函数声明和定义中的缺省值可能不同;
- 半缺省参数必须从右往左依次给出,不能间隔给出;
- 缺省值必须是常量或者全局变量。
函数重载
什么是函数重载
C++中允许在同一作用域中声明几个功能类似的的同名函数,这些同名函数的形参列表不同,常用来处理功能类似而数据个数/类型不同的函数的问题。需要注意的是,函数的返回值不在函数重载的定义范围内,返回值不同的函数不构成重载。借助函数重载,一个函数名可以有多种用途。
形参列表不同有三种情况:
- 参数数量不同
- 参数类型不同
- 参数类型顺序不同
// 1.参数个数不同
int Sum(int a, int b)
{
return a + b;
}
int Sum(int a, int b, int c)
{
return a + b + c;
}
// 2.参数类型不同
double Sum(double x, int y)
{
return x + y;
}
// 3.参数类型顺序不同
double Sum(int x, double y)
{
return x + y;
}
C++如何支持函数重载
要清楚 C++ 如何支持函数重载,就要先了解 C 为何不支持函数重载。假设有 test.c 和 Add.c 两个文件,分别使用和定义了Add函数,在多文件编译时,test.c和Add.c会单独编译形成各自的目标文件(.o),在链接的合并段表和符号表阶段,由于test.o中的符号表中的没有Add函数的有效地址,所以会在Add.o的符号表中寻找Add函数的定义(有效地址),并将Add的临时地址替换为有效地址。在C中,函数名是直接作为符号体现在符号表中的,这就会造成一个问题:当有多个函数名相同的函数时,链接器无法判断将哪个函数地址作为所使用函数的有效地址,便会报出重定义的链接错误。
在C++中,编译器在编译时会将函数名进行修饰,函数名修饰时与函数的名称和参数列表有关,每两个函数名相同而参数列表不同的函数经过修饰后便会有不同的名称,由此,在链接阶段,链接器便能正确选择对应的函数名已实现有效地址的填充。
每个编译器的函数名修饰规则不尽相同,下面以 gcc 和 g++ 编译器为例分别演示对 C 和 C++ 编译后的函数名。
可以发现,gcc未对 test.c 中的Add函数进行函数名修饰;而经过g++对test.cpp中的Add函数名修饰后变成了变成了[_Z+函数长度+函数名+参数类型首字母]
的形式,以保证后序进行链接的正确性。
了解C++支持函数重载的原理之后,需要额外明晰的是,函数的返回值类型不构成函数重载的原因与函数名修饰无关,例如,考虑这种情况:函数的参数列表都相同,仅仅只有返回值类型不同,即使将返回类型加入函数名修饰,因为调用函数时并不能明确返回值类型,所以编译器也不能到底判断调用哪个函数。
int func(double a, double b)
{
return a + b;
}
double func(double a, double b)
{
return a + b;
}
int main()
{
//此时编译器也不能判断该调用哪个函数,编译报错
cout << func(3.2, 5.7) << endl;
return 0;
}
标签:空间,函数,int,缺省,C++,Part1,命名
From: https://blog.51cto.com/158SHI/6193866