您可以实现这一点,但需要付出一些代价:
在 C++ 中,您可以有内部链接。未命名命名空间内的任何内容都具有内部链接*(见脚注),以及静态自由函数(您应该更喜欢匿名命名空间)。
更新:这是来自§3.5,4的 C++11 标准引用:
未命名的命名空间或在未命名的命名空间中直接或间接声明的命名空间具有内部链接。所有其他命名空间都有外部链接。具有命名空间范围但没有在上面给出内部链接的名称,如果它是
一个变量的名称,则它与封闭命名空间具有相同的链接;或者
——一个函数;或
— 命名类(第 9 条),或在 typedef 声明中定义的未命名类,其中该类具有用于链接目的的 typedef 名称(7.1.3);或
— 命名枚举 (7.2),或在 typedef 声明中定义的未命名枚举,其中枚举具有用于链接目的的 typedef 名称 (7.1.3);或
- 属于具有链接的枚举的枚举数;或者
——一个模板。
但是,内部链接适用于翻译单元,而不适用于静态库。因此,如果您使用通常的方法将每个类放在其自己的翻译单元 (=cpp) 中,则无法在匿名命名空间中定义它们,因为您无法将它们链接在一起以构建库。
您可以通过使整个库成为一个单一的翻译单元来解决这个难题:一个提供库的公共接口的标头,一个带有函数定义的源,以及在匿名命名空间中定义的任何其他标头:
mylib.hpp
class MyLib {
public:
int foo();
double bar(int i);
};
mylib.cpp
#include "mylib.hpp"
#include "mylibimpl.h"
int MyLib::foo() {
return fooimpl();
}
double MyLib::bar(int i) {
return BarImpl(i).do();
}
mylibimpl.h
namespace {
inline int fooimpl() { return 42; }
class BarImpl {
double d;
public:
BarImpl(int i) : d(i*3.42) {}
double do() { return 2*d; }
};
}
您现在将拥有一个翻译单元 ( mylib.o
/ mylib.lib
),并且所有的*impl
类和函数都无法从外部看到,因为它们具有内部链接。
代价是您必须重新组织内部类的源代码(例如解决循环依赖),并且库内部代码的每一次简单更改都会导致库中所有内容的大重新编译,因为只有一个巨大的翻译单元。因此,只有在库代码本身非常稳定或库不太大的情况下,才应该这样做。除了完全隐藏内部符号之外的好处是编译器将能够提取它想要的任何优化,因为没有实现细节隐藏在不同的翻译单元中。
*脚注:
正如 Billy ONeal 所评论的,在 C++03 中,匿名命名空间中的实体不一定具有内部链接。但是,如果它们具有外部链接,则它们具有对其翻译单元唯一的名称,并且实际上无法从该 TU 外部访问,这意味着该过程也适用于 C++03。