【C++】命名空间详解

2024-01-25 08:27:39 浏览数 (2)

前言

在C/C 中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存 在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化, 以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

代码语言:javascript复制
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C语言没办法解决类似这样的命名冲突问题,所以C  提出了namespace来解决
int main()
{
    printf("%dn", rand);
    return 0;
}
// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”

命名冲突: C 要求所有标识符都是无歧义的。如果将两个相同的标识符引入到同一程序中,而编译器或链接器无法区分它们,则编译器或链接器将产生错误。此错误通常称为命名冲突。 如果将冲突标识符引入到同一文件中,则结果将是编译器错误。如果将冲突标识符引入到属于同一程序的单独文件中,则结果将是链接器错误。

命名空间的定义

命名空间是一个区域,允许您在其内部声明名称以消除歧义。命名空间为其中声明的名称提供了一个作用域区域(称为命名空间作用域),这仅仅意味着在命名空间内声明的任何名称都不会被误认为是其他作用域中的相同名称。

在命名空间中声明的名称不会被误认为是在另一个作用域中声明的相同名称。

在命名空间中,所有名称都必须是唯一的,否则将导致命名冲突。

在命名空间域内,可以包含以下内容: ① 变量、对象以及它们的初始化。 ② 枚举常量。 ③ 函数声明以及函数定义。 ④ 类、结构体声明与实现。 ⑤ 模板。 ⑥ 其他命名

代码语言:javascript复制
namespace test
{
	int a = 10;
	int rand = 10;//变量
	int add(int x, int y)//函数
	{
		return x   y;
	}
	struct Node//结构体
	{
		struct Node* next;
		int val;
	};
}

嵌套命名空间

代码语言:javascript复制
namespace N1
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left   right;
	}
	namespace N2
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}

同一个工程中允许存在多个相同名称的命名空间,编译器最后会合并成一个命名空间

如,一个工程中的test.h和上面test.cpp中两个N1会被合并成一个

代码语言:javascript复制
// test.h
namespace N1
{
int Mul(int left, int right)
{
return left * right;
}
}

注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中

代码语言:javascript复制
namespace A
{
	int a = 10;
}
namespace B
{
	int a = 20;
}

int main()
{
	cout << A::a << endl;
	cout << B::a << endl;
}

不同命名空间内可以存在相同名称的变量,二者互不影响

命名空间的使用

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

代码语言:javascript复制
namespace A
{
	int a = 10;
}
namespace B
{
	int a = 20;
}

int main()
{
	cout << A::a << endl;
	cout << B::a << endl;
}

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

代码语言:javascript复制
using N::b;
using std::cin;
using std::cout;
using std::endl;
int main()
{
    printf("%dn", N::a);
    printf("%dn", b);
    cout<<b<<endl;
    return 0;
}

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

这个方法在平时做题时可以使用,但是在正式的工程项目中不建议使用,因为全部展开可以会发生命名冲突。

代码语言:javascript复制
using namespce N;
int main()
{
    printf("%dn", N::a);
    printf("%dn", b);
    Add(10, 20);
    return 0;
}
  • 命名空间域内部封装的在展开之后相当于在全局域
  • 命名空间的展开是将命名空间域打开,编译器搜索时可以到命名空间里搜索,命名空间不展开时,编译器不会到命名空间里搜索
  • 包含头文件的展开是在预处理阶段将头文件的内容拷贝到源文件里

0 人点赞