(一一二)名称空间

在C++之中,名称可以是变量、函数、结构、枚举、类以及类和结构的成员。随着项目的增大,名称相互冲突的可能性也将增加。

 

使用多个厂商的类库时,可能导致名称冲突。

 

例如两个类库都定义了名称为List、Tree和Node的类,但定义的方式并不兼容(一个干这个,一个干那个),如果你需要使用第一个的List,第二个的Tree,你就不能一口气把两个类库都包含进去(就像using namespace std和using std::cout那样),这会导致冲突,被称为名称空间问题。

 

 

声明区域:

是可以在其中进行声明的区域(也就是声明后,影响的范围,但这个范围不一定每个地方能使用这个变量)。

①在函数外声明全局变量:其 声明区域 为其声明所在的文件(还记得extern int a;声明了才能在该文件中用这个全局变量么?);

②函数内部声明:其 声明区域 为其声明所在的代码块(如果是函数,则在函数起作用,如果是在if(a>1){using namespace std;...}这样,那么就只能在这个if语句判断后的那个代码块里面起作用);

 

 

潜在作用域:

变量的潜在作用域,从声明点开始,到其声明区域的结尾。因此潜在作用域比声明区域小。

例如函数内部第二行声明了变量,其声明区域为整个函数,但其潜在作用域为第二行声明后到函数最后一行。

 

 

需要注意是,变量并不一定能在潜在作用域的任何一个地方使用。例如链接性为内部静态变量隐藏了同名的外部变量。

 

 

变量对于程序来说,可见的范围,被称为 作用域(scope)

 

 

 

C++关于全局变量和局部变量的规则,定义了一种名称空间层次。每个声明区域都可以声明名称,这些名称独立于在其他区域声明的名称。在一个函数中声明的局部变量,不会和另一个函数中声明的局部变量发生冲突。(也就是说,两个函数里,都可以有int a=1;这样的声明,他们不是同一个变量a)

 

 

 

新的名称空间特性:

是C++新增的一种功能,即通过定义一种新的声明区域来创建命名的名称空间,这样做的目的之一是提供一个声明区域的名称,一个名称空间的名称,不会和另外一个名称空间的相同名称发生冲突。同时允许程序的其他部分使用该名称空间中声明的东西。

 

创建名称空间的关键字是:namespace

如代码:

#include<iostream>

namespace aa	//创建名称空间aa
{
	int a;
}
namespace bb	//创建名称空间bb
{
	int b;
}

int main()
{
	using namespace std;

	using namespace aa;	//声明了才能使用变量a
	a = 1;
	cout << a << endl;

	using namespace bb;//声明了才能使用变量b
	b = 5;
	cout << b << endl;

	system("pause");
	return 0;
}

输出1和5

 

 

 

名称空间的特性:

①名称空间可以是全局的,也可以位于另一个名称空间之中,但不能位于代码块之中创建;

 

②默认情况下,在名称空间之中声明的名称的链接性为外部的(除非他引用了常量)(比如const int a=5; 然后名称空间的int b=&a这样?不确定);;

 

③除了用户定义的名称空间外,还存在另一个名称空间——全局名称空间。他对应于文件级声明区域。

因此前面所说的 全局变量 现在被描述为位于 全局名称空间 中。(所以全局变量才能每个文件都能用?)

 

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

因此假如上面的bb名称空间之中也有一个int a,那么也是可以共存的,同时也可以和外部的int a共存。

 

⑤名称空间之中的声明和定义规则,同全局声明和定义规则。

也就是说,如果名称空间aa中声明int a,那么如果两个不同的文件(但在同一个程序之中)引用这个名称空间aa,会导致认为是多重定义。

例如在头文件之中声明名称空间aa(内有int a),然后在1.cpp和2.cpp文件里都引用这个头文件,然后引用这个名称空间,并想要使用这个变量a,就会提示说多重定义。

 

⑥名称空间是开放的,可以把名称加入到已有的名称空间中。方法是多次定义(在函数外),例如代码:

namespace bb
//创建名称空间bb

{

int b;

}

namespace bb { int c; };

 

这个时候,名称空间bb里面有了int b和int c两个变量。

需要注意的是,不要在函数内部进行这个行为,会提示“不允许进行名称空间定义”。

 

 

 

⑦可以在名称空间中添加 函数原型 和 函数定义。这样,就可以通过调用名称空间后,直接使用名称空间中的函数。

 

 

 

名称空间的使用方法:

三个方法:

①using namespace 名称空间名 。这种办法可以在作用域里随意使用(就像cin和std::cin的使用差别那样)

②名称空间名::名称空间中的函数名/变量名  。比较麻烦的使用方法

③using 名称空间名::名称空间的变量/函数名  。只需要名称空间中的某一个名称时的使用方法

 

如代码:

#include<iostream>

namespace aa	//创建名称空间aa
{
	int a;
}

namespace bb	//创建名称空间bb
{
	void abc()
	{
		std::cout << "111" << std::endl;
	}
}

namespace cc
{
	double c = 1.1;
}

int main()
{
	using namespace std;	//方法一,很常见

	using namespace aa;	//方法一,using namespace 名称空间名
	a = 1;
	cout << a << endl;

	bb::abc();	//方法二,(作用域解析运算符::)名称空间名::名称空间中的函数名/变量名

	using cc::c;	//方法三,using 名称空间名::名称空间的变量/函数名
	cout << c << endl;	

	system("pause");
	return 0;
}

注意:
①方法①和③可能带来同名变量的冲突(会导致二义性),而方法②不会;

②方法①和③的作用范围,存在一个作用域的问题(具体根据情况而定);而方法②不存在作用域,只有在用的时候有效。

 

 

 

使用using namespace 名称空间名和using 名称空间名::名称空间的变量/函数名的区别:

①后者就像声明了一个变量一样,假如有一个同名变量,那么可能导致冲突;

 

②前者如果遇见外部的同名变量,会暂时隐藏起来外部同名变量;

 

③使用前者后,如果又在函数内部声明同名变量,那么单纯使用这个同名变量,使用的是函数内部后声明的,而不是名称空间的那个。

 

④在②③的情况下,依然可以使用全局同名变量。

如代码:

#include<iostream>

namespace aa
{
	int a=5;	//名称空间中的a
}
int a = 1;	//全局变量a

int main()
{
	using namespace std;

	using namespace aa;
	int a = 10;	//函数内部的变量a
	cout << a << endl;	//函数内部的a
	cout << ::a << endl;	//全局变量a
	cout << aa::a << endl;	//名称空间a

	system("pause");
	return 0;
}

输出:

10
1
5
请按任意键继续. . .

⑤在④的情况下,(注意有2个冒号)

::变量名 为全局变量,

名称空间::变量名 为名称空间声明的变量,

变量名 为函数内部的变量。

 

⑥如果把④中的代码,改为using aa::a;编译器会提示多次初始化,会出错。

 

⑦在不发生这种冲突的情况下,使用后者会更安全一些(即使冲突了,编译器也会提示,不像前者那样会隐藏外部变量,导致结果不是预期中的那样)。

 

 

 

#include<iostream>  using namespace std;的原理:

这两行代码的意思是,把iostream这个头文件放到名称空间std之中,然后using编译指令,是其在某个函数或整个文件中都可用(视using这条指令的位置而定)。

 

但若全局可用,其实并不好,容易导致某些冲突。所以尽量是函数内部使用,或者干脆使用上面的方法②和方法③。

 

 

 

名称空间的其他特性:

①嵌套。

例如把b名称空间嵌套在a中。

(1)如果b里面有一个变量c,需要这么引用他“using a::b::c”;

(2)如果引用名称空间b,需要这么用“using namespace a::b”;

(3)引用名称空间a,则是“using namespace a”(但并不代表同时引用了名称空间b);

即假如要引用名称空间b中的变量,要在普通引用那样之前,再加上“a::”这个前置。

有名称空间嵌套:

namespace aa

{

int a=5;
//名称空间中的a

namespace bb

{

int b = 10;

}

}

几种情况:

(1)using namespace aa;

(1.1)需要调用a,直接用a;

(1.2)需要调用b,需要用bb:b 或using namespace bb(然后才能直接用b)或using bb::b(同上一个);

(2)using namespace aa::bb;

(2.1)需要调用a,使用aa::a或者using编译指令/声明;

(2.2)需要调用b,直接使用b;

(3)无(1)和(2)

(3.1)需要调用a,使用aa::a或using编译指令(以下略后者);

(3.2)需要调用b,使用aa::bb::b;

 

 

 

②假如在一个名称空间中,添加了using namespace 另一个名称空间名,如代码:

namespace bb
//需要注意这个在下面那个之前,下面才能使用using namespace bb;否则会出错

{

int b = 10;

}

namespace aa

{

int a=5;
//名称空间中的a

using namespace bb;

}

几种情况:

(1)需要调用b,

(1.1)使用using namespace bb或另一个using声明(以下省略这个补充说明),然后直接用b。

(1.2)使用using namespace aa,然后直接调用b,或使用aa::b或bb::b,但不要使用aa::bb::b这样,会出错。

(2)需要调用a:和普通使用没区别;

(3)使用using namespace aa;等价于同时使用了using namespace bb;。

 

 

 

③创建别名。

创建别名方法:namespace 别名=某个名称空间名

如代码:

namespace bb
//需要注意这个在下面那个之前,否则会出错

{

int b = 10;

}

namespace c = bb;

 

 

 

未命名的名称空间:

假如一个名称空间未命名,

首先,不能被引用(因为没有名字,没办法使用using编译指令);

其次,其相当于默认使用了using编译指令(即创建后立刻被使用);

第三,其作用域为声明点到文件末尾(注意,不能在函数内部创建名称空间),即里面的名称,链接性为内部(其他文件不能用);

最后,相当于提供了链接性为内部的静态变量的替代品(即在这样的名称空间内部的变量int a;相当于没有在这里面的static int a;)。

 

 

 

名称空间里若有函数:

①至少要有函数定义,而不是只有函数声明,没有函数定义;

②可以函数定义和函数声明都有;

③若只有函数声明,函数定义在外部,可能导致出错。例如代码:

#include<iostream>

namespace bb	//需要注意这个在下面那个之前,否则会出错
{
	void abc(int );
}
using namespace bb;

int main()
{
	using namespace std;
	abc(1);	//会提示有多个重载函数与参数列表匹配
	system("pause");
	return 0;
}

void abc(int a)
{
	std::cout << a << std::endl;
}

会提示出错。

 

 

 

名称空间的一些指导原则:

①使用已命名的名称空间中声明的变量,而不是使用外部全局变量;

 

②使用已命名的名称空间中声明的变量,而不是使用静态全局变量;

 

③如果开发了一个函数库或者类库,将其放在一个名称空间中。

事实上,C++提倡将标准函数库放在名称空间std中,这种做法扩展到了来自C语言中的函数。例如,头文件math.h是与C语言兼容的,并没有使用名称空间,但C++头文件cmath应将各种数学库函数放在名称空间std中。但并非所有编译器都完成了这种过度。

 

④仅将编译指令using(指像using namespace std这样,而不是using std::cout这样,后者为using声明)作为一种将旧代码转换为使用名称空间的权宜之计。

 

⑤不要在头文件之中使用using编译指令;

首先,这样掩饰了要让哪些名称可用;

另外,包含头文件的顺序可能影响程序的行为;

如果非要用,请放在所有预处理器编译指令#include之后。

 

⑥导入名称时,首选使用作用域解析运算符或using声明方法(例如using std::cout这样);

 

⑦对于using声明,首选将其作用域设置为局部,而不是全局。

 

ps:①、②、④不太明白

 

 

 

总结:

①使用名称空间的主旨,是简化大型编程项目的管理工作。对于只有一个文件的简单程序,使用using编译指令并非什么大逆不道的事情。

 

②头文件名的变化,反应了名称空间的变化,例如老式头文件(如iostream.h)没有使用名称空间,而新式头文件iostream使用了std名称空间。

时间: 2024-11-03 04:24:33

(一一二)名称空间的相关文章

创建、查询、修改带名称空间的 XML 文件的例子

xml|创建 XML的应用越来越广泛了,如Vista.Flex编程都将使用 XML,正确掌握XML的各种操作,对提高编程效率至关重要.下面就是一个综合处理带名称空间的XML的例子.C#:string w3NameSpace = "http://www.w3.org/2000/xmlns/";System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); //创建根节点System.Xml.XmlNode root = doc.Cre

.net下对具有名称空间的XML使用XPath的方法

xml    这两天都在对一个其他公司提供的RSS接口进行编程,由于他们RSS提供的是1.0版本,其中的XML部分是有名称空间的,为此这一两天为了这个,摔了很多跟头,Unicode 编码的问题,XPath 的问题,XSLT 解析的问题.下面把这些问题的解决方法罗列出来,方便后来者.         使用 XPath 的问题: 由于存在名称空间,你的XPath需要额外的通过 XmlNamespaceManager 类进行一些设置.这个方法是我在:http://www.error-bank.com/

ASPX文件中默认导入的名称空间

ASPX默认导入的名称空间可以直接引用了,使用其它的名称空间就的自行导入了. 默认名称空间  System  System.Collections  System.Collections.Specialized  System.Configuration  System.Text  System.Text.RegularExpressions  System.Web  System.Web.Caching  System.Web.Security  System.Web.Se

PHP教程:PHP代码中的名称空间

在 PHP V5.3 中引入的名称空间是为 PHP 类.常量和函数提供上下文的一种方式,从而可以将使用相同名称的元素看作是惟一的.惟一的名称避免了命名冲突,当两个类或函数使用相同的名称时就会发生这种情况.有时这些 PHP 类表示现实世界中的相同对象,但它们的行为是完全不同的.名称空间能够确保您拥有正确的 PHP 类.常量或函数,并且要使用您的 PHP 类的人能够确保他们使用了正确的类. 代码中的名称空间就像现实世界中的上下文.考虑一个表示现实世界中的汽车对象的类.例如,通过 Internet 销

C#名称空间 VS Java包

   写了几天的C#程序,程序总会先声明一个名称空间:    namespace test    跟C++里名称空间一样,只是声明方法不同:   using namespace std;    名字空间是用来按照逻辑,对类进行划分,增强了程序的可读性,而且减少了命名的冲突.看到这个作用,我忽然想到了Java中的包,这两种东西感觉作用一致,都是为了避免名称冲突才进行一种区域性的划分的.    例如,java程序开头,总会先引入一些包:   import java.util.*;    这句话放在最

C#同一个名称空间里,两个类,A类中有个单击事件,B类有个方法

问题描述 C#同一个名称空间里,两个类,A类中有个单击事件,B类有个方法 怎么实现A中一单击就B中方法就执行????? 谢谢!!!!!!! 解决方案 a.Click += new EventHandler((se, ar) => { b.方法(参数...); }); 解决方案二: 事件不是A自己响应的,是A实例的持有者响应的. 到响应的地方去调用B实例的方法(除非是静态方法,普通方法必须有实例才能调用). 解决方案三: 在a的单击事件中写: new B().click(); 解决方案四: usi

《C++游戏编程入门(第4版)》——1.3 使用std名称空间

1.3 使用std名称空间 C++游戏编程入门(第4版)因为经常要用到std名称空间中的元素,在此介绍两种不同的可以直接使用这些元素的方法,这样就不必总是使用std::前缀. 1.3.1 Game Over 2.0程序简介 Game Over 2.0程序的运行结果和图1.2所示的原始Game Over程序一模一样,但是区别在于访问std名称空间中元素的方式.从Cengage Learning网站(www.cengageptr.com/downloads上可以下载到该程序的代码.程序位于Chapt

在 XML Schema和WSDL中使用名称空间

对于名称空间,理解了OO思想的人应该是比较简单的了,特别是对学过C++的人来说更是如此;但很多看了我前面文章的朋友,在和我的交流中,好像对名称空间都不怎么清楚,下面我们就来说说怎么样在 XML Schema和WSDL中使用名称空间.先看看一段JAVA代码: package com.hongsoft.test.pkg1; import com.hongsoft.test.pkg2.Test1; import com.hongsoft.test.pkg2.Test2;在这个文件中,我们把com.ho

【js拾遗】名称空间

function NameSpace(ns) { if (!ns) { return null; } var arr = ns.split('.'); //第一次调用的时候window.utry的值为{}; //第二次调用的时候window.utry的值为window.utry; window[arr[0]] = window[arr[0]] || {}; //obj是window.utry的引用 var obj = window[arr[0]]; //result也是window.utry的引