命名空间
C/C++中,变量、函数和类都是大量存在的。这些变量、函数和类都将存在于全局作用域中,可能会有很多冲突。使用命名空间的目的就是对标识符的名字进行本地化,以避免命名冲突和名字污染,于是namespace关键字出现了。
命名空间定义
定义命名空间:用namespace关键字,后面跟命名空间的名字,然后是一对 {},{}中即为命名空间中的成员。
//1.命名空间下可以放函数,变量和类,结构体以及命名空间
//2.命名空间必须定义在全局作用域下
//3.命名空间可以嵌套命名空间
namespace A {
void func();
int m_A = 20;
struct Person {};
class Animal {};
namespace B {
int m_A = 30;
}
}
//4.命名空间是开放的,可以随时往原先的命名空间添加内容
namespace A { //此命名空间会和上面的A命名空间合并
int m_B = 100;
}
//5.无名、匿名命名空间
namespace {
int m_C = 20;
int m_D = 30;
}
//当写了无名命名空间,相当于写了 static int m_C=20,static m_D=30;
//只能在当前文件内使用
//6.命名空间可以起别名
namespace veryLongName {
int m_A = 0;
}
void test04() {
//起别名,和veryLongName是一样的
namespace veryShortName = veryLongName;
cout << veryLongName::m_A << endl;
cout << veryShortName::m_A << endl;
}
命名空间的使用
namespace N
{
int a = 10;
int b = 20;
int Add(int left, int right)
{
return left + right;
}
int Sub(int left, int right)
{
return left - right;
}
}
int main()
{
printf("%d\n", a); // 该语句编译出错,无法识别a。命名空间的内容只存在于命名空间中。
return 0;
}
使用命名空间的三种方法
方法1:加命名空间名称及作用域限定符
int main(){
cout<<N::a<<endl; //注意是两个 :
cout<<A::B::m_A<<endl;//当命名空间下还有命名空间,要这样访问。
}
方法2:使用using将命名空间中的成员引入
using N::b;//说明之后访问b都是这个成员变量。
int main(){
cout<<b<<endl;
}
namespace D {
int b=20;
}
int main()
{
using D::b;
int b = 30;
cout << b << endl;
system("pause");
}
//这种情况下将报错,b重定义,多次初始化。
方法3:使用using namespace命名空间名称引入
using namespace N;//这句代码相当于打开了 N这个房间。而没有使用房间里面的东西。
int main(){
int a=10;
cout<<N::a<<endl;
cout<<a<<endl; //不会报错。
return 0;
}
函数默认参数
默认参数是声明或定义函数时为函数的参数指定一个默认值。再调用函数时,如果没有指定实参则采用该默认值,否则使用指定的默认值。
默认参数例子
void test(int a=10){
cout<<a<<endl;
}
int main(){
test(); //输出10
test(20);//输出20
}
默认参数分类
//全默认参数
void test(int a=10,int b=20,int c=30){
cout<<"a:"<<a<<"b:"<<b<<"c:"<<c<<endl;
}
//半默认参数
void test(int a,int b=20,int c=30){
cout<<"a:"<<a<<"b:"<<b<<endl;
}
注意:
■ 1、默认参数必须从右往左一次给出,不能间隔着给出。
■ 2、默认参数函数不能再声明和定义中同时出现,因为编译器不知道以哪个为标准。
■ 3、参数必须是常量或全局变量。
■ 4、C语言不支持默认参数。
函数重载
函数重载的具体可以参见我的另一篇博客:C/C++源文件到可执行文件、C++能重载C语言不能重载本质
内联函数
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提高程序的运行效率。内联函数的引入是为了解决预处理宏的缺陷。
预处理宏的缺陷
在C++中我们可以使用:1、常量定义用const定义常量。2、函数定义换用内联函数定义。
缺陷一:导致代码可读性差、可维护性差、容易误读
//示例一:
#define ADD(x,y) x+y
void test(){
int ret1 = ADD(10, 20) * 10; //希望的结果是300
cout << "ret1:" << ret1 << endl; //210
}
//实例二:
#define compare(x,y) ((x)<(y)?(x):(y))
void test02(){
int a=1,b=2;
cout<<compare(++a,b)<<endl;
}
缺陷二:预定义宏函数没有作用域概念、无法作为一个类的成员函数,也就是说预定义宏没有办法表示类的范围
缺陷三:不方便调试宏(预编译阶段进行了替换)、没有类型检查
预处理宏的优点
预定义宏的优点:提高代码的复用性。提高性能。
内联函数的特性
1、inline是一种空间换时间的做法,省去调用函数的开销。所以代码很长或者有递归的时候不宜使用内联函数。
2、inline对于编译器只是一个建议,编译器不一定会接受这样的建议。编译器会自动优化,如果定义为inline的函体内有循环/递归等,编译器优化时会自动忽略内联。任何在类内部定义的函数自动成为内联函数。
3、inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。因为内联函数没有地址,所以不能对内联函数取地址。