目录
1.命名空间
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
例如,在C++标准库std中存在大量的标识符,这些标识符存在于全局域,如果不用命名空间加以区分,容易导致编译链接时出错,比如下面这段代码无法通过编译
#include <iostream>
int rand = 5; // rand存在于std中,这里全局定义的rand会与std命名空间中的std形成冲突
int main()
{
printf("%d\n", rand); // 这里会报错,rand指向一个地址,即rand函数的地址
}
正确的做法是将自己定义的rand放在自己定义的命名空间,将其进行本地化,然后使用作用域符::来指明所选用的作用域
如何定义一个命名空间
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{ }即可,{ }中即为命名空间的成员。
namespace myspace // 定义一个命名空间myspace
{
int rand = 6;
}
int main()
{
printf("%d\n", myspace::rand); // 指定使用myspace中的rand变量
}
如果在文件中定义了两个类,在这两个类中可以有同名的函数,在引用时,为了区别,应该加上类名作为限定
namespace myspace1
{
// 命名空间内可以定义变量,函数,命名空间
int rand = 6;
int Add(int left, int right)
{
return left + right;
}
namespace myspace2 // 命名空间内部可以嵌套命名空间
{
int rand2 = 7;
int Sub(int left, int right)
{
return right - left;
}
}
}
namespace myspace3
{
int rand = 8; // 相同的变量名在不同的命名空间中不会发生冲突
}
int main()
{
printf("rand in myspace1 is : %d\n", myspace1::rand);
printf("rand in myspace3 is : %d\n", myspace3::rand);
printf("Add in myspace1 is uesd : %d\n", myspace1::Add(3, 5));
printf("Sub in myspace2 is uesd : %d\n", myspace1::myspace2::rand2);
return 0;
}
注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
using的用法
C++中using关键字通常有三种用法
- using声明(引入单个变量名)
- using指示(引入命名空间)
- 类型重定义(代替typedef)
using声明是将命名空间中某个名字单独引入到当前作用域,这使得我们在当前作用域下可以直接使用该名字而无需使用作用域限定符 ::
using std::cout; // 将std标准库中的cout和endl引入到全局域,使用时无须再指明std命名空间
using std::endl;
int main()
{
cout << "It's a test string" << endl; // 在这里直接使用
return 0;
}
using指示就是将一个 命名空间中的所有名字全部引入当当前作用域(或者说将命名空间在当前作用域展开)
using namespace std;
namespace myspace
{
int rand = 6;
int Add(int left, int right)
{
return left + right;
}
}
using namespace myspace; // 将myspace命名空间展开
int main()
{
std::cout << Add(3, 5) << std::endl; // 直接使用
return 0;
}
但这种直接展开的方式很容易造成不同域中相同变量之间冲突,建议减少使用
因此,对于命名空间和using展开,一般原则是
- 项目中,尽量不要使用using namespace std;
- 日常练习中使用using std;
- 项目中指定命名空间访问+展开常用
2.缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,
- 如果没有指定实参则采用该默认值
- 否则使用指定的实参
int func(int parameter = 10) // 给定一个缺省值10
{
return parameter;
}
int main()
{
std::cout << "Use defult:" << func() << std::endl; // 使用缺省值
std::cout << "Not use default: " << func(20) << std::endl; // 不使用缺省值,传参
}
缺省又分为全缺省和半缺省
全缺省中,所有的形参都被赋予缺省值,使用的时候可以不传参数也可以传入部分参数(从左往右传入)
int func(int parameter1 = 10, int parameter2 = 20, int parameter3 = 30)
{
return parameter1 + parameter2 + parameter3;
}
int main()
{
std::cout << "Use defult:" << func() << std::endl; // 60
std::cout << "Not use default: " << func(20, 30, 40) << std::endl; // 90
std::cout << "use part of default: " << func(20, 30) << std::endl; // 80
}
半缺省中,部分形参被赋予缺省值,使用的时候只有被赋予缺省值的部分不用传参,其余部分必须传参,在这里有个规则
- 半缺省参数必须从右往左依次来给出,不能间隔着给
- 缺省参数不能在函数声明和定义中同时出现
// case 1 ———— work
// 未缺省 缺省 缺省
int func(int parameter1, int parameter2 = 20, int parameter3 = 30)
{
return parameter1 + parameter2 + parameter3;
}
// case 2 ———— wrong
// 缺省 未缺省 缺省
int func(int parameter1 = 10, int parameter2, int parameter3 = 30)
{
return parameter1 + parameter2 + parameter3;
}
// case 3 ———— wrong
// 缺省 未缺省 未缺省
int func(int parameter1 = 10, int parameter2, int parameter3)
{
return parameter1 + parameter2 + parameter3;
}
当一个函数的声明和定义同时存在时
// 在声明中给好缺省值
int func(int parameter1, int parameter2 = 20, int parameter3 = 30);
// 定义中不再给缺省值
int func(int parameter1, int parameter2, int parameter3)
{
return parameter1 + parameter2 + parameter3;
}