前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【C++】命名空间

【C++】命名空间

作者头像
修修修也
发布2024-04-01 16:14:26
730
发布2024-04-01 16:14:26
举报

🎏命名空间的由来

在C++开发过程中,大型程序往往会使用多个独立开发的库,这些库又会定义大量的全局名字,如类,函数和模板等。当应用程序用到多个供应商提供的库时,不可避免地会发生某些名字相互冲突的情况。多个库将名字放置在全局命名空间中将引发命名空间污染(namespace pollution)。

如下情况,C语言是无法解决类似的冲突问题的:

代码语言:javascript
复制
#include<stdio.h>
#include<stdlib.h>

int rand = 10;
//rand是有关随机数的一个库函数

int main()
{
	printf("%d\n", rand);

	return 0;
}

如上代码在编译器中运行结果会有重定义错误:

传统上,程序员通过将其定义的全局实体名字设得很长来避免命名空间污染问题,这样的名字通常包含表示名字所属库的前缀部分:

代码语言:javascript
复制
class cplusplus_primer_Query{ ... };
string cplusplus_primer_make_plural(size_t,string&);

这种解决方案显然不太理想:对于程序员来说,书写和阅读这么长的名字费时费力且过于烦琐

命名空间(namespace)防止名字冲突提供了更加可控的机制。命名空间分割了全局命名空间,其中每个命名空间是一个作用域。通过在某个命名空间中定义库的名字,库的作者(以及用户)可以避免全局名字固有的限制


🎏命名空间的定义

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。 如下,我们定义了一个名为MFC的命名空间,里面包含了三个成员,分别是:变量min,函数Sum,结构体Stu:

代码语言:javascript
复制
namespace MFC
{
	//命名空间中可以定义变量/函数/类型

	int min = 1;

	int Sum(int a, int b)
	{
		return a + b;
	}

	struct Stu
	{
		struct Stu* next;
		char name[10];
	};
}

📌每个命名空间都是一个作用域

和其他作用域类似,命名空间中的每个名字都必须表示该空间内的唯一实体。因为不同命名空间的作用域不同,所以在不同命名空间内可以有相同名字的成员。


📌命名空间是可以嵌套的

如下A2命名空间就嵌套在A1里:

代码语言:javascript
复制
//命名空间可以嵌套
namespace A1
{
	int a;
	int b;
	int Sum(int sum1, int sum2)
	{
		return sum1 + sum2;
	}

	namespace A2
	{
		int c;
		int d;
		int sub(int sub1, int sub2)
		{
			return sub1 - sub2;
		}
	}
}

📌命名空间可以是不连续的

命名空间可以定义在几个不同的部分,同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中:


🎏命名空间使用的三种方式

📌加命名空间名称及作用域限定符

这种命名空间的使用方式是仅在使用某个变量的时候去找到它存在的命名空间然后将它单独展开使用。 这种使用方式适合于只在程序中使用一两次的变量/函数/类型,这种使用方式可以有效防止命名空间大幅度展开造成的命名污染,但缺点是当该成员要使用多次时,每次都在使用时展开,会导致代码逻辑比较繁琐。 如下,这次展开的作用范围就仅仅在printf()函数中才有用:

代码语言:javascript
复制
namespace MFC
{
	//命名空间中可以定义变量/函数/类型
	int min = 1;

	int Sum(int a, int b)
	{
		return a + b;
	}

	struct Stu
	{
		struct Stu* next;
		char name[10];
	};
}

int main()
{
	printf("%d\n", MFC::min);

	return 0;
}

📌使用using将命名空间中某个成员引入

这种命名空间的使用方式是在全局范围将命名空间中的某个成员引入,此时,该变量在工程中就相当于一个全局变量,此时在整个工程中就可以直接使用该成员了. 这种是我们一般比较推荐的命名空间使用方式,因为它既不会像单独展开那样导致代码太过繁琐,又不会像命名空间全部展开那样导致大面积的命名污染. 如下,18行使用using展开的成员min就可以在主函数内直接使用了:

代码语言:javascript
复制
namespace MFC
{
	//命名空间中可以定义变量/函数/类型
	int min = 1;

	int Sum(int a, int b)
	{
		return a + b;
	}

	struct Stu
	{
		struct Stu* next;
		char name[10];
	};
}

using MFC::min;

int main()
{
	printf("%d\n", min);

	return 0;
}

📌使用using namespace命名空间名称引入

这种命名空间的使用方式是在全局范围将整个命名空间引入。此时,该命名空间的所有成员都被引入到了工程中,此时在整个工程中就可以直接使用该命名空间的所有成员了. 这种方式会将命名空间里的所有成员都暴露在全局中,是我们最不推荐的一种使用方式,因为这样极易造成不经意间的命名空间污染问题. 如下,18行使用using namespace展开的命名空间MFC里的成员就可以在主函数内直接使用了:

代码语言:javascript
复制
namespace MFC
{
	//命名空间中可以定义变量/函数/类型
	int min = 1;

	int Sum(int a, int b)
	{
		return a + b;
	}

	struct Stu
	{
		struct Stu* next;
		char name[10];
	};
}

using namespace MFC;

int main()
{
	printf("%d\n", min);
	printf("%d\n", Sum(1, 2));

	return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🎏命名空间的由来
  • 🎏命名空间的定义
    • 📌每个命名空间都是一个作用域
      • 📌命名空间是可以嵌套的
        • 📌命名空间可以是不连续的
        • 🎏命名空间使用的三种方式
          • 📌加命名空间名称及作用域限定符
            • 📌使用using将命名空间中某个成员引入
              • 📌使用using namespace命名空间名称引入
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档