C++ namespace(域)

个人主页:Jason_from_China-CSDN博客

所属栏目:C++系统性学习_Jason_from_China的博客-CSDN博客

namespace的价值

  1. 避免命名冲突:在大型项目或使用多个库的情况下,不同部分可能会定义相同名称的实体(如变量、函数、类等)。使用命名空间可以有效地避免这些命名冲突。【这一点的尤其关键的,在C语言里面,是没有域这样的区分之说的,所以会导致命名的冲突,尤其的当命名应该新变量的时候,如果引入新的库,会导致命名错误,就需要大量的修改命名,这会很麻烦。但是在C++里面,我们只需要在外层封装一层就可以了】

//这个C语言的代码就是有问题的,因为引入了新的库,从而导致需要更改命名,
//这里还是比较少的代码,如果代码数量比较多,那么就会存在大量重复的代码的工作
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
// 编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”
printf("%d\n", rand);
return 0;
}
  1. 组织代码逻辑:命名空间可以将逻辑相关的代码组织在一起,使得代码结构更加清晰,便于理解和维护。

  2. 提供上下文:命名空间提供了一种上下文,使得程序员可以快速了解某个实体属于哪个模块或库。

  3. 支持大型项目开发:在大型项目中,可能需要包含多个库和子系统,命名空间的使用可以确保这些不同的部分在全局作用域中不会相互干扰。

  4. 促进代码重用:命名空间允许程序员在不同的上下文中重用相同的名称,而不必担心名称冲突,从而提高了代码的重用性。

  5. 简化代码编写:使用命名空间后,程序员可以在不同的命名空间中定义具有相同名称的变量或函数,简化了代码编写。

  6. 支持模块化开发:命名空间支持模块化开发,每个模块可以有自己的命名空间,从而实现代码的解耦。

  7. 提高编译效率:编译器在查找未限定名称时,会先在局部作用域查找,然后是类作用域,接着是命名空间作用域,最后是全局作用域。这种分层次的查找顺序可以提高编译效率。

  8. 便于代码维护:当需要修改或更新某个模块时,只需要关注该模块的命名空间,减少了对其他模块的影响。

  9. 支持语言的扩展性:随着 C++ 语言的发展,新的库和特性不断加入,命名空间的使用确保了新旧代码可以和谐共存,不会因新特性的加入而导致现有代码出现问题。

namespace定义

  • 定义命名空间,需要使用到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
  • namespace本质是定义出⼀个域,这个域跟全局域各自独立,不同的域可以定义同名变量,所以下面的rand不在冲突了。
  • C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期。
  •  namespace只能定义在全局,当然他还可以嵌套定义。
  • 项目工程中多文件中定义的同名namespace会认为是⼀个namespace,不会冲突。
  • C++标准库都放在⼀个叫std(standard)的命名空间中
  • namespace是C++基础关键字,不需要什么头文件

namespace单层的书写和调用

这里Js是命名空间的名字,一般在开发里面用项目的名字为命名空间的名字

这里我是随意起了一个名字

域里面也是可以书写函数和结构体等等的

//namespace只能定义在全局,当然他还可以嵌套定义。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
namespace Js
{
	int c = 10;
	int ADD(int a, int b)
	{
		return a + b;
	}
}
int main()
{
	printf("%d", Js::c);
	return 0;
}
  1. #include<stdio.h>:这是另一个预处理指令,用于包含标准输入输出库的头文件。这个库提供了 printf 函数,它在 main 函数中被用来输出。

  2. namespace Js { ... }:这里定义了一个名为 Js 的命名空间。命名空间是一种封装机制,用于组织代码,防止命名冲突。在这个命名空间中:

    • int c = 10; 定义了一个名为 c 的整型变量,并初始化为 10
    • int ADD(int a, int b) { ... } 定义了一个名为 ADD 的函数,它接受两个整型参数 a 和 b,并返回它们的和。
  3. int main() { ... }:这是程序的主函数,程序从这里开始执行。

    • printf("%d", Js::c); 在这里,Js::c 表示对命名空间 Js 中的成员变量 c 的引用。printf 函数使用 Js::c 作为参数,输出 c 的值,即 10

总结来说,Js::c 是对 Js 命名空间中定义的静态成员变量 c 的引用。在 main 函数中,通过 Js::c 访问该变量,并使用 printf 函数将其值输出到控制台。

这里可以看到结果,进入到命名空间里面访问c,c我们初始化给的数值是10,所以访问的时候就是10

::域作用限定符

域作用限定符这里主要的作用就是访问域里面的变量或者函数

下面的如果看不懂没关系,直到域作用限定符在这里面是干什么用的就可以

  • 访问全局变量或函数:当局部作用域(如函数内部)中存在与全局作用域中同名的变量或函数时,可以使用 :: 来指定访问全局作用域中的实体。

//C++的输出方式
int globalVar = 10; // 全局变量

void function() {
    int localVar = 20; // 局部变量
    std::cout << ::globalVar << std::endl; // 访问全局变量
}
//C语言的输出方式
int a = 110;
int main()
{
	printf("全局变量的a=110,局部变量的a=11\n\n\n");
	int a = 11;
	printf("不加域作用限定符:%d\n\n\n", a);
	printf("加上域作用限定符:%d\n\n\n", ::a);

}

  • 访问命名空间中的成员:在包含多个命名空间的情况下,:: 用于指定访问特定命名空间中的成员。

namespace A {
    int value = 5;
}

namespace B {
    int value = 10;
}

int main() {
    std::cout << ::A::value << std::endl; // 输出 A 命名空间中的 value
    std::cout << ::B::value << std::endl; // 输出 B 命名空间中的 value
}
  • 访问类的静态成员:在类的作用域内部访问静态成员时,需要使用 :: 来指定。

class MyClass {
public:
    static int staticVar;
};

int MyClass::staticVar = 0; // 定义静态成员

void function() {
    MyClass::staticVar = 1; // 在类外访问静态成员
}
  • 解决作用域冲突:当嵌套作用域中存在同名实体时,:: 用于解决这些冲突,明确指定要访问的实体。

int outerVar = 1;

void outerFunction() {
    int innerVar = 2;
    std::cout << ::outerVar << std::endl; // 访问外部变量
}
  • 访问枚举类型的值:在 C++11 之前,枚举类型没有强类型支持,使用 :: 可以访问枚举中的值。

enum Color { RED, GREEN, BLUE };

int main() {
    std::cout << ::RED << std::endl; // 访问 RED 枚举值
}

namespace嵌套的书写和调用

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
namespace Js
{
	int c = 10;
	int ADD(int a, int b)
	{
		return a + b;
	}
	namespace js1
	{
		int d = 30; int f = 20;
		int del(int d, int f)
		{
			return d - f;
		}
	}
	namespace js2
	{
		int d = 30; int f = 20;
		int ADD(int d, int f)
		{
			return d + f;
		}
	}
}
int main()
{
	printf("namespace单层调用测试:%d\n", Js::c);

	int ret = Js::js1::del(30, 10);
	printf("namespace多层调用测试:%d", ret);
	return 0;
}

最终效果

  1. 在调用的时候,我们可以利用域作用限定符
  2. 进入到我们需要的域里面调用函数,并且选择接收。
  3. 我们既可以初始化,也可以选择传参,和C语言里面函数的使用是一样的。只是多了一层的封装。

namespace多文件定义-同变量名

在 C++ 中,命名空间(namespace)是一种封装机制,用于组织代码并防止名称冲突。当你在多个文件中定义同名的命名空间时,C++ 编译器会将这些命名空间视为同一个命名空间的扩展。这意味着不同文件中定义的同名命名空间的成员实际上是共享的,它们属于同一个逻辑上的命名空间。

这种特性非常有用,因为它允许你将大型项目分解为多个模块或文件,每个模块都有自己的命名空间,同时又能够保持命名空间的一致性和统一性。

File1.cpp:

namespace MyProject {
    void function1() {
        std::cout << "Function 1" << std::endl;
    }
}

File2.cpp:

namespace MyProject {
    void function2() {
        std::cout << "Function 2" << std::endl;
    }
}

在这两个文件中,我们都定义了名为 MyProject 的命名空间,并在其中分别定义了 function1function2。当我们编译和链接这两个文件时,MyProject 命名空间将被视为同一个命名空间,function1function2 都将是 MyProject 命名空间的成员。

你可以在 main 函数或其他任何地方这样调用它们

int main() {
    MyProject::function1(); // 调用 File1.cpp 中定义的 function1
    MyProject::function2(); // 调用 File2.cpp 中定义的 function2
    return 0;
}

等同于一个域:

多⽂件中可以定义同名namespace,他们会默认合并到⼀起,就像同⼀个namespace⼀样

namespace MyProject {
    void function1() {
        std::cout << "Function 1" << std::endl;
    }
    void function2() {
        std::cout << "Function 2" << std::endl;
    }
}

当然,如果你两个域封装的函数名字也一样,但是作用不一样,那么我们只需要再封装一下就可以。

namespace实际项目举例

实际使用

如图

当为同一个命名空间下面,我们还可以嵌套定义。

防止同一个项目组命名冲突

这样就增加了团队合作的协作性,而且这里有一个关键,是C语言没有的,就是不同域之间的命名冲突是不会导致报错的,因为域的不同,但是如果域相同命名一样,还是会导致冲突,解决方式就只需要再封装一下就可以,所以这里我们就可以发现C++比C语言优势多了很多了

 namespace命名空间的展开

命名空间的展开顾名思义就是不需要继续进入到域里面了,直接就可以访问

命名空间展开的弊端和使用规则:

展开命名空间(风险很大,平时写的小算法,写的小项目,没有那麽多的冲突的时候,是可以直接展开,命名空间)

展开指定的命名空间:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
namespace Js
{
	int c = 10;
	int ADD(int a, int b)
	{
		return a + b;
	}
	namespace js1
	{
		int d = 30; int f = 20;
		int del(int d, int f)
		{
			return d - f;
		}
	}
	namespace js2
	{
		int d = 30; int f = 20;
		int ADD(int d, int f)
		{
			return d + f;
		}
	}
}
int a = 110;
//int main()
//{
//	printf("全局变量的a=110,局部变量的a=11\n\n\n");
//	int a = 11;
//	printf("不加域作用限定符:%d\n\n\n", a);
//	printf("加上域作用限定符:%d\n\n\n", ::a);
//
//	printf("namespace单层调用测试:%d\n\n\n", Js::c);
//
//	int ret = Js::js1::del(30, 10);
//	printf("namespace多层调用测试:%d\n\n", ret);
//
//	//展开命名空间
//
//	return 0;
//}

using namespace Js;
int main()
{
	int c = 0;
	printf("展开命名空间,访问局部空间有的变量:%d\n\n\n", c);
	printf("展开命名空间,访问局部空间有的变量:%d", ::c);

	return 0;
}
  • 这里可以发现,::域作用限定符存在依旧是会首先访问全局变量,不存在会首先访问局部变量
  • 这里已经展开Js这个域,所以c就暴露在全局变量了

展开嵌套的命名空间:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
namespace Js
{
	int c = 10;
	int ADD(int a, int b)
	{
		return a + b;
	}
	namespace js1
	{
		int d = 30; int f = 20;
		int del(int d, int f)
		{
			return d - f;
		}
	}
	namespace js2
	{
		int d = 30; int f = 20;
		int ADD(int d, int f)
		{
			return d + f;
		}
	}
}
int a = 110;
//int main()
//{
//	printf("全局变量的a=110,局部变量的a=11\n\n\n");
//	int a = 11;
//	printf("不加域作用限定符:%d\n\n\n", a);
//	printf("加上域作用限定符:%d\n\n\n", ::a);
//
//	printf("namespace单层调用测试:%d\n\n\n", Js::c);
//
//	int ret = Js::js1::del(30, 10);
//	printf("namespace多层调用测试:%d\n\n", ret);
//
//	//展开命名空间
//
//	return 0;
//}

using namespace Js;
using namespace Js::js2;
int main()
{
	int c = 0;
	printf("展开外层命名空间,访问局部空间有的变量:%d\n\n\n", c);
	printf("展开外层命名空间,访问局部空间有的变量:%d\n\n\n", ::c);

	int d = 00;
	printf("展开嵌套内层命名空间,访问局部空间有的变量:%d\n\n\n", d);
	printf("展开嵌套内层命名空间,访问局部空间有的变量:%d\n\n\n", ::d);

	return 0;
}

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在C++中,命名空间(namespace)是一种用来避免名称冲突的机制。当工程越大,使用多个厂商的类库时,名称冲突的可能性就越大。为了避免这种冲突,C++引入了命名空间的概念。命名空间可以将一组相关的标识符包装在一个作用内,从而限制其在程序中的可见性。通过使用命名空间,可以更好地控制标识符的作用,避免名称冲突。\[2\] 在C++中,可以使用命名空间嵌套来组织代码。当命名空间嵌套层次太多时,使用其中的成员会变得很麻烦。为了方便使用,可以对嵌套的命名空间取别名。通过使用别名,可以简化代码中对命名空间成员的访问。例如,在代码中可以使用"namespace alias_kzl = kxl::kdl::kzl;"来为"kxl::kdl::kzl"命名空间取别名为"alias_kzl"。然后可以通过"alias_kzl::y"来访问"kxl::kdl::kzl"命名空间中的"y"成员。\[1\] 在使用命名空间时,有多种方式可以引入命名空间中的成员。一种常见的方式是使用"using"关键字,例如"using namespace std;"可以将"std"命名空间中的成员引入当前作用。然而,这种方式可能会导致名称冲突和不明确的代码。因此,一种更好的做法是使用限定符来访问命名空间中的成员,例如"std::cout"。这样可以明确指定使用的是哪个命名空间中的成员,避免冲突和歧义。\[3\] #### 引用[.reference_title] - *1* [C++ namespace](https://blog.csdn.net/kjl167/article/details/126244107)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [C++ namespace用法详细介绍](https://blog.csdn.net/Yifancoder/article/details/124127828)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C++ namespace详解](https://blog.csdn.net/weixin_30808575/article/details/96584787)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值