C++编程知识之命名空间

时间:2024-01-25 10:17:28

命名空间

一、命名空间的定义

1.命名空间的由来:一个大型的工程往往是由若干个人独立完成的,不同的人分别完成不同的部分,最后再组合成一个完整 的程序。由于各个头文件是由不同的人设计的,有可能在不同的头文件中用了相同的名字来命名所定义 的类或函数,这样在程序中就会出现名字冲突。不仅如此,有可能我们自己定义的名字会与C++库中的 名字发生冲突。 名字冲突就是在同一个作用域中有两个或多个同名的实体,为了解决命名冲突 ,C++中引入了命名空 间,所谓命名空间就是一个可以由用户自己定义的作用域,在不同的作用域中可以定义相同名字的变 量,互不干扰,系统能够区分它们。

2.命名空间的定义: 命名空间又称为名字空间,是程序员命名的内存区域,程序员根据需要指定一些有名字的空间域,把一 些全局实体分别存放到各个命名空间中,从而与其他全局实体分隔开。通俗的说,每个名字空间都是一 个名字空间域,存放在名字空间域中的全局实体只在本空间域内有效。名字空间对全局实体加以域的限 制,从而合理的解决命名冲突。

3.命名空间的基本格式

namespace 命名空间的名字
{
    定义的变量;
}

注意:大括号内不仅可以存放变量,还可以存放:变量、常量、函数(可以是定义或声明 )结构体、类、模板以及可以嵌套定义的命名空间。

代码案例

namespace ff
{
	int number = 100;
	struct Foo
	{
		char ch;
		int val;
	};
	void play();
}

定义在名称空间中的变量或者函数都称为实体,名称空间中的实体作用域是全局的, 并不意味着其可见域 是全局的。 如果不使用作用域限定符和using机制,抛开名称空间嵌套和内部屏蔽的情况,实体的可见域是从实体创建到该名称空间结束。 **在名称空间外,该实体是不可见的。**但我们需要使用命名空间的实体的时候,就需要特殊的使用方法

二、命名空间使用方法

命名空间一共有三种使用方式,分别是using编译指令、作用域限定符、using声明机制

1.using编译指令

使用using编译指令,就会把该命名空间中的所有实体一次性引入到程序之中,例如

#include <iostream>
using namespace std
int main()
{
	cout << "hell,world" << endl;
	return 0;
}	

我们最常见的就是使用 using namespace std;,这个代码的意思就是引入了std这个命名空间,std是标准库(Standard Library)我们所熟知的cout、cin等就是在这个命名空间里的。

2.using声明机制

如果全部使用该命名空间的所有实体,只用部分,则需要使用using::实体名来实现,例如:

#include <iostream>
using std::cout;
using std::endl;
namespace wd
{
	int number = 10;
	void display()
	{
		cout << "wd::display()" << endl;
	}
}
using wd::number;
using wd::display;
int main()
{
	cout << "wd::number = " << number << endl;
	wd::display();
}

在给定的代码中,using关键字的作用域是从其声明位置开始直到当前作用域结束。具体来说,以下是using声明的作用域:

  1. using std::cout;using std::endl;的作用域是整个文件(全局作用域),因为它们位于#include <iostream>之后且在任何函数或命名空间定义之前。
  2. using wd::number;using wd::display;的作用域是wd命名空间内部和main()函数内部。这是由于这两个using声明位于namespace wdmain()函数之间。

main()函数中,可以直接使用numberdisplay,而无需加上命名空间前缀wd::。但是在其他命名空间或函数定义中,仍然需要使用完整的命名空间限定符才能访问wd命名空间中的标识符。要注意,在同一作用域内用 using声明的不同的命名空间的成员不能有同名的成员,否则会发生重定义。

3.作用域限定符

第三种方式就是直接使用作用域限定符::。每次要使用某个名称空间中的实体时,都直接加上,例如:

namespace dd
{
	int number = 10;
	void display()
	{
		std::cout << "wd::display()" << std::endl;//cout,endl都是std空间中的实体,所以都加上'std::'命名空间
	}
}
int main()
{
	std::cout << "wd::number = " << wd::number << endl;
	wd::display();
}

但因为比较冗余,所以不经常用。

三.匿名命名空间

命名空间还可以不定义名字,不定义名字的命名空间称为匿名命名空间。由于没有名字,该空间中的实体,其它文件无法引用,它只能在本文件的作用域内有效,它的作用域是从匿名命名空间声明开始到本文件结束。在本文件使用无名命名空间成员时不必用命名空间限定。其实匿名命名空间和static是同样的道理,都是只在本文件内有效,无法被其它文件引用。

#include <iostream>
using std::cout;
using std::endl;
int g_number2 = 10;
namespace 
{
	int number = 2;
	void print() 
    {
		cout << "hello,world" << endl;
    }
}

使用匿名命名空间,直接调用其函数即可

int main() {
    // 调用匿名命名空间中的变量和函数
    std::cout << "Number: " << number << std::endl;
    print();
    return 0;
}

同时,在C++中,static关键字有多重含义,其中之一就是用于限制变量或函数的作用域,使其仅在当前文件(或当前匿名空间)内可见。当我们在匿名空间中声明一个全局变量,并将其定义为static时,它的作用范围将被限制在该匿名空间内部。

由于该变量是全局变量,具有全局生存期,因此在程序的整个执行过程中都存在。然而,由于它的作用范围限制在匿名空间内部,外部的其他函数无法直接访问该变量。只有在同一匿名空间内的函数才能通过变量名来访问和操作这个static全局变量。

四.命名空间的跨模块调用

以上述代码为例子,改为非匿名命名空间,并且建立MyNameSpace.cpp文件

#include <iostream>
using std::cout;
using std::endl;
int g_number2 = 10;
namespace SC
{
	int number = 2;
	void print() {
	cout << "hello,world" << endl;
}

然后建立一个新的MyNameSpace1.cpp文件,列入以下代码

#include <iostream>
#include "MyNameSpace.cpp"
// 引入命名空间
using namespace myNameSpace;
int main() {
    // 调用命名空间中的函数
    print();
    return 0;
}
//或者不使用using,直接使用作用域限定符即可
	SC::print();

即可完成对命名空间的跨模块调用

五.命名空间的嵌套和覆盖

#include <iostream>
using namespace std;
int number = 1;
namespace wz
{
	int number = 10;
	namespace wh
	{
		int number = 100;
		void display()
		{
			cout << "wz::wh::display()" << endl;
		}
	}
    
	void display(int number)
	{
		cout << "形参number = " << number << endl;
		cout << "wz命名空间中的number = " << wz::number << endl;
		cout << "wh命名空间中的number = " << wz::wh::number << endl;
	}
}
int main(void)
{
	using wz::display;
	display(1);
   	wz::wh::display();
	return 0;
}

将会产生以下结果

形参number = 1
wz命名空间中的number = 10
wh命名空间中的number = 100
wz::wh::display()

每一个步骤:

  1. 在全局作用域中定义了一个全局变量number,其值为1。
  2. 定义了命名空间wz,在其中定义了一个局部变量number,其值为10。
  3. wz命名空间中定义了另一个命名空间wh,在其中定义了一个局部变量number,其值为100,并定义了函数display()
  4. wz命名空间中的display()函数中,输出了形参number的值,即10。
  5. 输出了wz命名空间中的number变量的值,即1。
  6. 输出了wz::wh命名空间中的number变量的值,即100。
  7. 调用了wz::wh::display()函数,输出了"wz::wh::display()"。

参考文献来自于王道的C++命名空间讲义,有删改。