Chinaunix首页 | 论坛 | 博客
  • 博客访问: 593426
  • 博文数量: 98
  • 博客积分: 4045
  • 博客等级: 上校
  • 技术积分: 1157
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-31 16:56
文章分类

全部博文(98)

文章存档

2010年(7)

2009年(15)

2007年(73)

2006年(3)

我的朋友

分类: C/C++

2007-11-28 11:44:52

命名空间(namespace)在C 中作用非同一般。本文目不在于阐述命名空间语法,而在于演示命名空间使用方法,或者说是使用命名空间小窍门。

  命名空间可以简单将一些命名(name)用另一个命名打包封装起来。比方说:

namespace net {
  class Socket {
    ...
  };
}
...
net::Socket socket;
经过这样封装以后,如果在两个库(library)都实现了Socket类,只要它们命名空间名字不同,你就可以同时使用它们而没有任何命名上冲突。

  但这样做还是有问题:假如两个公司都要写一个network库,那么当她们编写代码时候都使用Socket命名他们类可能性有多大?我猜是接近100%。

  命名空间名字最是方便输入,就是说命名空间名字最好别太长了,2-4个字符就可以了。抱着这样想法,那两个公司把他们的命名空间叫做net机会又是多大呢?5%还是10%?

  不难看出,命名空间并没有解决所有问题,它只是使发生命名冲突的机会相对小了而已。

  有一种叫做“工业化长度”的方法(Industrial Strength Solution),这种方法在命名namespace时候使用长唯一名称,而在程序里使用短别名。如此network库就可能会是这个样子:

namespace net_33843894 {
  class Socket {
    ...
  };
}
net_后面的数字是由一个随机数产生器产生。为了以后描述方便,这里我们假定上面的代码是放在头文件里。

  用户使用我们的库时候,就要编写他自己的头文件,包含下面的内容:

#include
namespace net = net_33843894;
他创建了一个在本工程内有效的别名,用来代表提供给他库中的命名空间。如果名称net已经被别库使用了,那么他还可以另选一个名字代替,例如:net2,sock,或者别的什么。

  这样就万事大吉了么?还没有。你还要做一件事:使你的库用起来更简单、更方便。在这个讲究完美社会里,人们双击一个安装文件后,你的库在他们开发环境里就应该是可用的,接下来就是#include ,再接下来他们就可以去忙别的了。

  然而,现在的情况是,用户为了使用你库需要创建一个他自己的头文件,虽然这并没有什么大不了,但不是每个用户都能忍受这一点。解决的方法就是直接提供一个合理缺省值,如果用户觉得不合适也可以取消,所以,在你的头文件里使用预编译选项,如下:


namespace net_33843894 {
  class Socket {
    ...
  };
}
#ifndef NO_NET_33843894_ALIAS
  namespace net = net_33843894;
#endif
这样我们就给命名空间的名字提供了一个缺省值,如果这个名字已经有人用了,那么用户可以定义一个NO_NET_33843894_ALIAS宏,别名就会被取消。

  不幸的是,即使是使用了短别名net,当你使用Socket类的方法不对时候,在我所用过的编译器中,没有一个能够在错误提示信息里显示短的别名,而是仍然使用net_33843894::Socket。读起来有些费劲。

  怎么办?看我的。

#ifdef NO_NET_33843894_ALIAS
namespace net_33843894 {
#else
namespace net {
#endif
  class Socket {
    ...
  };
}
#ifndef NO_NET_33843894_ALIAS
  namespace net_33843894 = net;
#endif
如果没有定义宏NO_NET_33843894_ALIAS, 就直接给命名空间起个短一点的名字,把别名弄长点就可以了。这样,错误信息读起来就会顺眼多了。
阅读(3788) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~