您的位置:首页 > 其它

using声明与using指示的区别(在作用域上)

2015-11-13 12:41 309 查看
在《C++ Primer》第五版十八章中详细描述了 using 指示与 Using 声明的区别,个人也想了好久。首先,明确一下 using 声明与指示

using 声明: using std::cout;

using 指示: using namespace std;

1.初步展示区别

在我们通常的理解下,using 声明引入了一个名字,在声明之后的作用域中,所有用到该名字的地方,都是指的改名字。而using 指示则是将命名空间中的所有名字都引入当前作用域,效果有些类似若干个 using 声明。但事实上,这两个是存在很大的不同的。看以下例子:

(1)对using 声明:

namespace N1
{
	int a = 0;
}

void f()
{
	using N1::a;  //此时下文中所有的 a 都将等效为 N1::a
	int a = 4;    //这句话将会导致编译器报重复定义的错误,因为 a 已经定义为 int a = 0,此时再次定义就重定义了
	cout << a << endl;
}


(2)对 using 指示

namespace N1
{
	int a = 0;
}

void f()
{
	using namespace N1;
	int a = 4;  //此时将不会报错,程序正常运行
	cout << a << endl;  //输出4,可见N1::a 被屏蔽
}


由上面的例子可以看出,using 指示与 using 声明不仅仅是包含进来的命名空间的名字数目不同的区别。

2.两者在作用域上的区别

(1)using 声明

“从效果上看就好像using声明语句为命名空间的成员在当前作用域中创建了一个别名一样” ——《C++ primer》5th

从书中的原话上看出,using 声明语句的作用效果是从当前语句开始,在当前作用域中余下部分若提到该成员,则均指的是命名空间中的成员。如:

int i = 1;

namespace N
{
     int i = 2;
}

void f()
{
      cout << i <<  endl;  //输出1
      using N::i;          //从该语句开始的当前作用域中,所有 i 指的均是 N::i
      cout << i << endl;  //输出2
}


(2)using 指示

“它具有将命名空间成员提升到包含命名空间本身和using指示的最近作用域的能力”——《C++ primer》5th

这句话写的真的很绕,我所花费的时间都是在理解这句话,后来问了一下同学(skillness),才正确的对这句话进行了分句。首先这句话的分句如下:

它具有将命名空间成员提升到包含(命名空间本身和 Using 指示)的最近作用域的能力这里的最近作用域指的是该命名空间本身所在作用域与Using 指示这句话所在作用域的总作用域。而不是,命名空间和using
指示的最近作用域两个作用域
。如:

namespace C1
{
	namespace C2   //命名空间本身的作用域为 C1
	{
		int   i = 2;
	}
	namespace C3
	{
		namespace C4
		{
			void f()
			{
				using namespace C2;   //using 指示的作用域是 C4
				cout << i << endl;
			}
		}
	}
}
则包含命名空间本身的作用域C1与using指示所在作用域C4 的作用域是C1作用域。也就是说,对 using 指示所在有效作用于(f函数体内)而言,i 表现得好像是定义在C1 中的成员。

如果我的理解是正确的,那是不是说如果现在C1中也定义了i成员,f()函数中访问i成员就会出现二义性:首先是C2 中的i 被提升到 C1 中,其次是 C1 中自己定义的 i 成员。事实证明,此时就是会报二义性的错误,说明我的理解是对的。测试代码如下:

namespace C1
{
	int i = 1;
	namespace C2
	{
		int   i = 2;
	}
	namespace C3
	{
		namespace C4
		{
			void f()
			{
				cout << i << endl;  // 输出 1,C1::i
				using namespace C2; // 将 C2::i 提升到 C1 空间中
				cout << i << endl;  // 编译器将会提示:i 不明确
			}
		}
	}
}
可见,using 指示会将命名空间成员提升到包含双方所在作用域的大作用域中。而不是指的两个作用域!

在上述测试代码中,将 using 指示换成 using 声明将不会出错,因为此时相当于在当前作用域中引入了 C2::i,将会屏蔽外部嵌套命名空间中的同名成员。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: