C++命名空间深度解析
1.命名空间的价值
在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
举个例子:
#include int rand = 10; int main() { int rand = 1; printf("%d\n", rand); return 0; }
这是一个正确的C语言代码(但并不推荐这种写法),局部变量rand覆盖了全局变量的数值,能够正确运行。但是只要加入一个头文件,就会使程序运行错误,看:
报错信息显示,rand被重定义了,因为标准库中已经有一个名为rand()的函数(用于生成随机数)。为了避免这种情况,C++语言引进了namespace关键字。
2. namespace定义
• 定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
namespace hhy { int rand = 1; int Add(int x, int y) { return x + y; } struct Stu { int age; char name[10]; }; }
这是一个简单的命名空间,定义了一个变量,函数和结构体。
• namespace本质是定义出⼀个域,这个域跟全局域各自独立,不同的域可以定义同名变量,所以下面的rand不在冲突了。
#include //#include int rand = 10; namespace hhy { int rand = 1; int Add(int x, int y) { return x + y; } struct Stu { int age; char name[10]; }; } int main() { printf("%d\n", hhy::rand);//在hhy命名空间寻找rand变量 printf("%d\n", ::rand);//在全局变量中寻找rand变量 return 0; }
在 C 和 C++ 中,:: 是作用域解析运算符,用于访问全局作用域或特定命名空间中的标识符。
注意:这里将#include给注释了,不然第二次打印会报错,跟rand函数冲突,但第一次打印可以正常运行,大家可以去试一试。
• C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期。
#include using namespace std; // 全局作用域:变量lifeGlobal的生命周期从程序启动到结束 int lifeGlobal = 1; // 命名空间作用域:变量lifeNS的生命周期同样贯穿程序全程 namespace MyNS { int lifeNS = 2; } // 类作用域:静态成员变量lifeStatic属于类本身,而非类的实例 class MyClass { public: static int lifeStatic; // 声明静态成员变量 }; // 定义并初始化静态成员变量(在全局/静态存储区分配内存) int MyClass::lifeStatic = 3; // 测试函数:展示局部变量的生命周期 void testScopes() { // 局部作用域:变量lifeLocal的生命周期从函数调用开始,到函数返回时结束 int lifeLocal = 4; cout // 访问全局变量(直接使用变量名) cout int num1 = 10; namespace ty { int num2 = 20; } } int main() { cout int a = 0; int b = 1; } int main() { // 编译报错:error C2065: “a”: 未声明的标识符 printf("%d\n", a); return 0; } int a = 1; int b = 2; } //指定命名空间访问 int main() { printf("%d\n", N::a); return 0; } // using将命名空间中某个成员展开 using N::b; int main() { printf("%d\n", N::a); printf("%d\n", b); return 0; } // 展开命名空间中全部成员 using namespace N; int main() { printf("%d\n", a); printf("%d\n", b); return 0; }