我们的讨论基于下列准则:
1. 只限于namespace或global作用域的变量常量。函数内或Class内的不做讨论。
2. 如果是C程序,以下涉及匿名namespace处都该以static取代之。(虽然C++也可以用static,但更好的方式是匿名namespace)
3. 链接期变量定义只能在一个CPP中出现;常量则可以多次出现。
4. 被置于namespace内的东西必将成为私用,编译器会帮你约束不小心的extern。
5. 共享的东西至少声明应该出现在头文件中,私用的东西则不该出现在头文件中
1. 私用:应该放在CPP中,常量和变量都应该以namespace{}或者static(如果是C程序)包含之,
// xx.cpp
namespace {
int i = 100;
const int i = 200;
}
当然如果不用namespace{}约束,并且头文件中不声明语法也是个私用变量:
但这样有两个风险:
1. 万一在头文件中声明extern了,编译器不会帮你检查
2. 对变量而言,容易与其他CPP产生变量定义冲突。
所以应该使用namespace{}约束之。
2. 给多个CPP共享:
变量应该以extern声明于头文件,普通定义于CPP文件。
常量应该以普通定义于头文件:
// xx.h
extern int i;
const int x = 100;
namespace { const int& b = x; } // 注意引用并非编译其常量,故必须以namespace包含之。
// xx.cpp
int i = 10;
对于变量上面的方法仍可能产生链接期错误(如果另一个cpp有同名变量定义),那么你就不得不修改你的变量名,更好的方法是以非匿名的namespace约束之。如果此变量有可能在main()以外使用,那么你还不得不建立Meyers单件。
延伸讨论
1. 如果将匿名namespace置于头文件中会怎样?
首先虽然语法上不会招致错误,但绝不要这么做,因为逻辑上是自相矛盾的,你既想让位于匿名namespace中的东西私用,却又将其置于能够被他人共享的头文件中。
这么做的唯一后果就是在多个CPP中产生多份私用拷贝(无论对于常量还是变量),虽然这可能大大出乎你的意料(比如对于变量,你或许会认为可以在多个CPP中修改同一个变量)。
2. 如果将const定义于CPP中,再以extern const声明之,会怎样?
首先语法上虽然可以,但绝不要这么做。下列是针对extern const和直接定义const于头文件的一个比较:
用户习惯:后者更符合习惯,前者像从火星来的
效率:后者更高,因为做宏替换(编译期常量);前者成了运行期常量(其实值到运行期才能决定)
可维护性:前者更易维护(对实值得修改值影响本编译单元)。但是通常作为const的常量值更改的可能性很小(就像函数默认参数一样)。
所以更应该使用前者。
3. 运行期const不要置于头文件!
总结:
1. 首先应该尽量不要让名字暴露于全局空间,不论是变量还是常量
2. 头文件中绝不应该出现任何匿名namespace或者static(不包括定义与class定义式内的)
3. CPP文件中绝不应该出现非static(无论是常量或变量),除非是要extern 共享变量。
4. 应该这样做:
// .h
namespace var{
extern int sharei; // 共享变量
}
namespace con {
const int shareci = 100; // 共享常量
}
// .cpp
namespace var {
int sharei = 100;
}
namespace privateuse {
namespace {
int privatei = 10;
const int privateci = 10;
const int privateci = func(); 运行期const不要置于头文件!
}
}