使用namespace的正确方法

命名空间(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_后面的数字是由一个随机数产生器产生的。为了以后描述方便,这里我们假定上面的代码是放在<netlib>头文件里。

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

#include <netlib>

namespace net = net_33843894;

 

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

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

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

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, 就直接给命名空间起个短一点的名字,把别名弄长点就可以了。这样,错误信息读起来就会顺眼多了。

===============================================================================

Using Namespaces Properly

 

by Dejan Jelovic

 

Namespaces are a very powerful C++ language feature. This article does not teach you the syntax of namespaces. Rather, it shows you how to use them properly.

 

Namespaces simply wrap all enclosed names with another name. For example:

 

namespace net { class Socket { ... }; } ... net::Socket socket;

 

By doing that, they make sure that if two libraries both implement the Socket class, if they name their namespaces differently your program can use both without a conflict.

 

But this brings up another question: If two independent companies both decide to write network libraries, what are the chances that they are going to implement a class named Socket? My guess is somewhere around 100 percent.

 

We also like it when namespace names are easy to type, which means that they should be 2-4 characters long. With that in mind, what are the chances that both companies are going to name their namespace net? 5 percent? 10 percent?

 

Whatever it is, it shows that namespaces do not solve the problem, they only make it less severe.

 

An Industrial Strength Solution

 

The solution to this problem is to use long, unique namespace names, and then bring the namespaces into a program by using short aliases.

 

So a company writing the network library should write something like:

 

namespace net_33843894 { class Socket { ... }; }

 

where the number after net_ is going to be generated using a random number generator. Say this code is placed in a header file called <netlib>

 

Then the library is sold to a client, who decides to use it on a project. The client then writes his own project-local header file named <mynetlib>, with the following content:

 

#include <netlib> namespace net = net_33843894;

 

He has just created a project-local alias for the namespace of his library vendor. If the namespace name net had already been taken by another library, the user can choose another name: net2, sock, or something else. There will be no name conflicts.

 

Lowering Barriers

 

A smart thing to do with your library is to make it easy for people to start using it. In an ideal world, they should be able to double-click on an installation file and the library would be immediately available inside their development environment. Next thing they are typing is #include <yourlib> and they are using it to do something useful.

 

However, if the user has to make his own header for every header in your library, then he has to suffer a little bit in order to use it. Not every user will be willing to do so.

 

The solution to this problem is to provide reasonable defaults, but to let the users cop out of them if they are not suitable. The way to do this is with preprocessor directives in your header file:

 

namespace net_33843894 { class Socket { ... }; } 
#ifndef NO_NET_33843894_ALIAS namespace net = net_33843894; #endif

 

This way, we provide a reasonable default for the namespace name. If that name is already taken, then the user can define the macro NO_NET_33843894_ALIAS and no alias will be defined.

 

Current Compilers

 

Error messages are already a nightmare with templates. With long namespace names, we make them even worse.

 

Unfortunately, none of the compilers I use are smart enough to display an error with the shortest available namespace alias at the point of error. So even though you may be using the alias net, if you make an error using the Socket class the error will mention net_33843894::Socket. Not very readable.

 

So I use a little trick. It works only for headers that contain only inline functions (as it affects the actual names used by the linker), but I have plenty of those. If the macro NO_NET_33843894_ALIAS is not defined, I use the short name as the namespace name, and the long name as the alias:

 

#ifdef NO_NET_33843894_ALIAS namespace net_33843894 
{ #else namespace net { #endif class Socket { ... }; } 
#ifndef NO_NET_33843894_ALIAS namespace net_33843894 = net; #endif

And the error messages become bearable again.

====================================================================

 

来自:www.codeproject.com

标题: Using Namespaces Properly

作者: Dejan Jelovic

译者:受本人翻译水平限制,可能原文作者的本意并没有被完全准确的表达出来,如果你在阅读本文的过程中出现问题,你可以给我写信coolgrass@sina.com