【和春笋一起学C++】(三十二)名称空间

目录

[1 名称空间的定义](#1 名称空间的定义)

[2 名称空间的特点](#2 名称空间的特点)

[3 访问名称空间中的名称](#3 访问名称空间中的名称)

[3.1 using声明](#3.1 using声明)

[3.2 using编译指令](#3.2 using编译指令)

[3.3 using声明和using编译指令的比较](#3.3 using声明和using编译指令的比较)

[3.4 总结](#3.4 总结)


1 名称空间的定义

声明区域是可以在其中进行声明的区域。例如:代码块是一个声明区域,可以在其中声明自动变量,文件也是一个声明区域,可以在其中声明全局变量。

C++新增了一种功能,通过定义一种新的声明区域来创建命名的名称空间,一个名称空间中的名称不会与另一个名称空间中的相同名称发生冲突,同时允许程序的其他部分使用该名称空间中声明的东西。名称空间使用namespace创建,示例如下:

cpp 复制代码
namespace book
{
	double price;
	string series;
	string name;
}

namespace computer
{
	double price;
	string modelNumber;
	string name;
}

上述代码中创建了两个名称空间,book和computer,两个名称空间中都定义了price变量,但不会发生冲突,因为这两个price分别位于不同的名称空间中。

任何名称空间中名称都不会与其他名称空间中的名称发生冲突。

2 名称空间的特点

  1. 名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中。因此,默认情况下,在名称空间中声明的名称,其链接性为外部。
  2. 名称空间中的声明和定义规则与全局声明和定义规则相同。
  3. 名称空间是开放的,例如可以把paginalNumber变量加入到已有的名称空间book中,代码如下:
cpp 复制代码
namespace book
{
	double price;
	string series;
	string name;
}

namespace computer
{
	double price = 4999.0;
	string modelNumber;
	string name;
	void showProperties();
}

namespace book
{
	int paginalNumber;
}

namespace computer
{
	void showProperties()
	{
		cout << "cpu is Intel \n";
		cout << "Gpu is NVIDIA \n";
		cout << "RAM is 16G \n";
	}
}

原文为CSDN作者:三月微暖寻春笋


3 访问名称空间中的名称

访问名称空间中的名称最简单的方法是通过作用域解析操作符"::",并使用名称空间来限定该名称,使用作用域解析操作符访问上述定义的名称空间中的变量,如下所示:

cpp 复制代码
computer::showProperties();
double price = computer::price;

上面语句中,第二条语句中左边的price称为未限定的名称,右边包含名称空间的price被称为限定的名称。

3.1 using声明

C++提供了两种机制来对名称空间中名称的使用。

  • using声明使特定的名称可用;
  • using编译指令使整个名称空间中的名称都能被使用;

using声明由被限定的名称和它前面的关键字using组成。

示例代码1如下:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

namespace computer
{
	double price = 4999.0;
	string modelNumber;
	string name;
	void showProperties();
}

namespace computer
{
	void showProperties()
	{
		cout << "cpu is Intel \n";
		cout << "Gpu is NVIDIA \n";
		cout << "RAM is 16G \n";
	}
}

int main()
{
	using computer::price;
	computer::showProperties();
	double a= price;

	return 0;
}

程序说明:

using声明将特定的名称添加到它所属的声明区域中。上面程序中,main()函数中的语句:using computer::price;表示将computer名称空间中的price添加到main()函数代码块中,完成该声明后,可以使用price代替computer::price。

示例代码2,将上面程序中的main()函数改成如下:

cpp 复制代码
int main()
{
	using computer::price;
	computer::showProperties();
	double a= price;

	double price;
	return 0;
}

**程序说明:**当main()函数改成上面的代码后,编译将无法通过,因为在main()函数代码块中定义了两个局部的price,编译器将报"重定义"错误。

示例代码3:

cpp 复制代码
double price = 1.0;
int main()
{
	using computer::price;
	computer::showProperties();
	double a= price;//使用局部变量,computer::price
	double b = ::price;///使用全局变量price
	cout << "a=" << a << ", b=" << b << endl;
	return 0;
}

在main()函数外面定义了一个全局变量price,则在main()函数内声明的price将覆盖同名的全局变量。

输出结果如下:

程序说明:using computer::price;该语句将price声明为局部名称之后,在main()函数代码块中将覆盖全局变量price,如果要使用全局变量price,则需要使用作用域解析操作符"::"。

示例代码4:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

namespace computer
{
	double price = 4999.0;
	string modelNumber;
	string name;
}
void fun();
using computer::price;
int main()
{
	double a= price;
	cout << "a=" << a << endl;
	fun();
	return 0;
}

void fun()
{
	int b = price + 1;
	cout << "b=" << b << endl;
}

如果在main()函数外面使用using声明,则将把名称空间添加到全局名称空间中,在main()函数代码块和fun()函数代码块中都能使用price。输出结果如下:

3.2 using编译指令

using编译指令由名称空间名和它前面的关键字using namespace组成,using编译指令使名称空间中所有名称都可用,不需要再使用作用域解析操作符。将示例代码4中语句using computer::price;改成下面的语句,程序运行结果是一样的。

cpp 复制代码
using namespace computer;

在示例代码4的第三行也用了命名空间,using namespace std;,std名称空间是在iostream类中定义的,所以需要使用#include <iostream>预编译。

在函数中使用using编译命令,将使命名空间中的名称在该函数代码块中可用。例如,将示例代码1中的main()函数改成如下,其输出结果是一样的。

cpp 复制代码
int main()
{
	using namespace computer;
	computer::showProperties();
	double a= price;

	return 0;
}

using声明和using编译指令,它们都增加了名称冲突的可能性。

3.3 using声明和using编译指令的比较

使用using编译指令导入一个名称空间中所有的名称与使用多个using声明是不一样的。使用using声明时,就好像声明了相应的名称一样,如果某个名称在函数中已经声明了,则不能用using声明导入相同的名称,否则将导致重定义,在3.1的示例代码2中已经用实例说明了这个问题。但如果使用using编译指令导入一个已经在函数中声明的名称,则局部名称将覆盖名称空间中同名的名称。示例代码5,将示例代码1中的main()函数修改如下:

cpp 复制代码
int main()
{
	using namespace computer;
	int price = 1;
	double a= price;
	cout << "a=" << a << endl;
	return 0;
}

输出结果为:a=1。这是因此局部变量的名称price覆盖了名称空间computer中的price。

再来看一个实例,示例6:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

namespace computer
{
	double price = 4999.0;
	string modelNumber;
	string name;
	void showProperties();
}

double price = 999.0;
int main()
{
	using namespace computer;
	double price = 1;
	double a= price;

	cout << "a=" << a << endl;
	a = ::price;
	cout << "a=" << a << endl;
	a = computer::price;
	cout << "a=" << a << endl;
	return 0;
}

可以直接运行上面的代码,输出结果如下:

程序说明:第一行输出的变量a是局部变量price的值,第二行输出的变量a是全局变量price的值,第三行输出的变量a是名称空间中的price值。

三点结论:

  1. 局部声明的price将覆盖computer::price和全局price;
  2. 如果使用作用域解析操作符,则名称空间中的price和全局变量的price都是可用的;
  3. 名称computer::price被放在局部名称空间中,但其作用域不是局部的,因此不会覆盖全局的price;

3.4 总结

假设名称空间和声明区域定义了相同的名称,如果试图使用using声明将名称空间的名称导入该声明区域,则这两个名称将发生冲突,编译器会给出明确的指示。如果使用using编译指令将该名称空间的名称导入该声明区域,则局部版本将覆盖名称空间版本,编译能正常通过,编译器不会作出提示。

在使用名称空间时,即可以用using编译指令,也可以用using声明,还可以用作用域解析操作符。但建议少用using编译指令,尤其是在函数外使用using编译指令,这会将名称空间中的名称全部导出到全局名称空间中,容易导致命名空间泛滥。对于示例6程序,使用下面的代码将更好,更易于维护。

示例代码7:

cpp 复制代码
#include <iostream>
#include <string>

namespace computer
{
	double price = 4999.0;
	std::string modelNumber;
	std::string name;
	void showProperties();
}

double price = 999.0;
int main()
{
	using namespace computer;
	double price = 1;
	double a= price;

	std::cout << "a=" << a << std::endl;
	a = ::price;
	std::cout << "a=" << a << std::endl;
	a = computer::price;
	std::cout << "a=" << a << std::endl;
	return 0;
}