C++中的using

总用限定修饰的名字形式 namespace_name::member_name 来引用名字空间成员 毫无疑问是非常麻烦的 尤其是当名字空间名很长的时候 如果不得不一直使用限定修饰名 我们
可能会希望创建一些短名字的名字空间 不但因为它们易读 而且因为它们易于键入 但是使用短的名字空间名会增加与程序中的其他全局名冲突的可能性 所以用长的名字空间名来

发行我们的库更为合适一些幸运的是 有一些机制能够简化程序中的名字空间成员的用法 名字空间别名 using声明 using 指示符是帮助我们克服名字空间名使用上的这些不便之处的机制:

using 声明
通过使名字空间成员的名字可见 来在程序中用该名字的非限定修饰方式引用这个成员而不用前缀 namespace_name::name 也是可行的 如果该成员被用 using 指示符声明 那么这就能够做到这一点
using 声明以关键字 using 开头 后面是名字空间成员名 using 声明中的成员名必须是限定修饰名 例如
namespace cplusplus_primer {
namespace MatrixLib {
class matrix { /* ... */ };
// ...
}
}
// 名字空间成员 matrix 的 using 声明
using cplusplus_primer::MatrixLib::matrix;
using 声明在声明出现的域中引入了一个名字例如 前面的 using 声明向全局域引入了名字 matrix在遇到 using 声明之后 在全局域中或其嵌套的域中使用 matrix 都将引用该名字空间成员 例如 假设 using 声明后而又有下面的声明
void func( matrix &m );
该声明声明了函数 func() 它有一个参数 类型是 cplusplus_primer::Matrix::matrix
using 声明同其他声明的行为一样(就像一般的声明一样)  它有一个域它引入的名字从该声明开始直到其所
在的域结束
都是可见的 using 声明可以出现在全局域和任意名字空间中 同时它也可以出现在局部域中 与其他声明一样 using 声明引入的名字有以下特性:

1.它在该域(同一个域中)中必须惟一(记住:防止重复定义)
2.由外围域(相对于(大于)using声明所在的域)中的声明引入的相同名字被其隐藏
3.它被嵌套域相对于(小于)using声明所在的域中的相同名字的声明隐藏

例如
namespace blip {
int bi = 16, bj = 15, bk = 23;
// 其他声明
}
int bj = 0;
void manip() {
using blip::bi; // 函数 manip() 中的 bi 指向 blip::bi
++bi; // 设置 blip::bi 为 17
using blip::bj; // 隐藏全局域中的 bj
// 在函数 manip() 中的 bj 指向 blip::bj
++bj; // 设置 blip::bj 为 16
int bk; // bk 在局部域中声明
using blip::bk; // 错误: 在 manip() 中重复定义 bk(都在manip()函数这个域中)
}
int wrongInit = bk; // 错误: bk 在这里不可见 应该用 blip::bk
函数 manip()中的 using 声明以简短形式引用名字空间 blip 的成员 using 声明在 manip()函数之外并不可见 用户只能在 manip()函数内部使用这些短名字 在该函数之外 仍然必须使用限定修饰名  using 声明使名字空间成员易于使用 using 声明一次只能引入一个名字空间成员 它允许我们专门指定在程序中要使用的名字 在特定域中引入 using 声明 使我们可以明确地指定在哪些地方可使用名字空间成员的简短形式 在下一小节 我们将了解怎样一次引入一个名字空间的全部成员名


 
using 指示符

以关键字 using 开头 后面是关键字 namespace 然后是名字空间名 如果该名字没有指向一个前面已经定义的名字空间 则这是一个错误 using 指示符允许我们让来自特定名字空间的所有名字的简短形式都可见 这些成员可以被直接使用 而不要求其名字被限定修饰 例如前面的代码例子可以重写如下
#include "primer.h"
// using 指示符: cplusplus_primer 的所有成员都变成可见的
using namespace cplusplus_primer;
// 名字 matrix 和 inverse 可以不加限定修饰地被使用
void func( matrix &m ) {
// ...
inverse( m );
}
using 指示符使名字空间成员名可见 就好像它们是在名字空间被定义的地方之外被声明的一样 例如 由于 using 指示符 名字空间 cplusplus_primer 的成员就好像是在全局域中 func()定义之前声明的一样  using 指示符并没有为名字空间成员的名字声明局部的别名  而是把名字空间的成员转移到包含该名字空间定义的那个域中比如如下代码
namespace A {
int i, j;
}
对域中有如下 using 声明的代码来说
using namespace A;
看起来就像
int i, j;
我们来看个例子 它说明了 using 声明的影响 它保留了该名字空间域 但是将成员名与一个局部同义词相关联 以及 using 指示符的影响 其效果相当于去掉了该名字空间
namespace blip {
int bi = 16, bj = 15, bk = 23;
// 其他声明 using 指示符
名字空间是随标准 C++而引入的 标准 C++之前的实现并不支持名字空间 结果是标准 C++之前的库也不把全局声明包装在名字空间中 在各种 C++实现支持名字空间之前人们已经编写了大量重要的 C++代码及其应用程序 如果我们把一个库的内容封装到一个字空间内 那么我们也就潜在地打破了这些使用旧版本库的旧版应用程序 如果我们把该库的内容包装到一个名字空间中 则该库中的所有名字都变成被限定修饰的 即以该名字空间名加上域操作符作为前缀 而所有以短形式使用该库中的名字的应用程序都不奏效了 我们可以使用 using 声明使库中的名字变成可见的 例如 假设文件 primer.h 含有该库的新版本 它将全局声明包装到名字空间 cplusplus_primer 中 如果我们想让自己的程序能很快地和新库协同工作 那么就可以用两个 using 声明使名字空间 cplusplus_primer 中的类 matrix和函数 func()的名字变成可见的
我们来看个例子 它说明了 using 声明的影响 (它保留了该名字空间域 但是将成员名与一个局部同义词相关联 )以及 using 指示符的影响 其效果相当于去掉了该名字空间
namespace blip {
int bi = 16, bj = 15, bk = 23;
// 其他声明

}
int bj = 0;
void manip() {
using namespace blip; // using 指示符 -
// ::bj 和 blip::bj 之间的冲突只在 bj 被使用时才被检测到
++bi; // 设置 blip::bi 为 17
++bj; // 错误: 二义性
// 全局 bj 还是 blip::bj?
++::bj; // ok: 设置全局 bj 为 1
++blip::bj; // ok: 设置 blip::bj 为 16
int bk = 97; // 局部 bk 隐藏 blip::bk
++bk; // 设置局部 bk 为 98
}

应该注意的第一个问题 using 指示符是域内的 在 manip()中的 using 指示符只能应用在函数 manip()的块内对函数manip()来说 名字空间 blip 的成员就好像是在全局域中声明的一样所以 函数 manip()可以以简短形式引用这些成员的名字 在函数 manip()之外的代码必须使用限定修饰名
要注意的第二个问题是 由 using 指示符引起的
二义性错误(原因就在于using指示符代表的内容相对于其所在的域是外围域或全局域)是在该名字被使用时才被检测到 而不是在遇到 using 指示符时 例如 成员 bj 在 manip()中出现 就好像它是在名字空间 blip 被定义的地方之外 即全局域中 被声明的一样 然而 在全局域中已经有一个名为bj 的变量 因此 在函数 manip()中使用 bj 有二义性 该名字同时引用全局变量和名字空间blio 的成员 但是 using 指示符并没有错 只有当 manip()函数用到 bj 时 编译器才会检测到二义性错误 如果 bj 在 manip()中没有被用到 则不会产生错误
要注意的第三个问题是 使用限定修饰名不受 using 指示符的影响 当 manip()引用::bj时 只有全局域中的变量才被考虑 当 manip()引用 blip::bj 时 只考虑名字空间 blip 引入的变量
要注意的最后一个问题是 因为名字空间成员就好像是在 该名字空间定义所在的地方(at the location where the namespace definition is located —)之外被声明的一样 所以出现在manip()中的成员就好像是在全局域中被定义的一样 这意味着 manip()中的局部声明可以隐藏某些名字空间成员名 局部变量 bk 隐藏了名字空间成员 blip::bk 在 manip()中引用 bk 没有二义性 它引用的是局部变量 bk

考虑下面的代码例子
namespace Exercise {
int ivar = 0;
double dvar = 0;
const int limit = 1000;
}
int ivar = 0;
//1
void manip() {
//2
double dvar = 3.1416;
int iobj = limit + 1;

++ivar;
++::ivar;
}
如果将名字空间 Exercise 成员的 using 声明放在 //1 处 那么会对代码中的声明和表达式
有什么样的影响 如果放在 //2 处呢 当用 using 指示符代替名字空间 Exercise 的 using 声明
时 答案又是什么


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值