在C ++中声明/定义类范围常量的地方?

我很好奇C ++中不同的常量声明和定义选项的好处/坏处。 最长的时间,我只是在类定义之前在头文件的顶部声明它们:

//.h const int MyConst = 10; const string MyStrConst = "String"; class MyClass { ... }; 

虽然这污染了全局命名空间(我知道这是一件坏事,但是从来没有发现过这个糟糕的原因),常量仍然会被限制到单个的翻译单元,所以不包含这个头文件的文件将无法访问这些常量。 但是,如果其他类定义了一个同名的常量,那么可以得到名称冲突,这可能不是一件坏事,因为它可能是一个可以重构的区域的好迹象。

最近,我决定在类定义本身内部声明类特定的常量会更好:

 //.h class MyClass { public: static const int MyConst = 10; ... private: static const string MyStrConst; ... }; //.cpp const string MyClass::MyStrConst = "String"; 

常量的可见性将根据常量是仅在类内部使用还是用于其他使用该类的对象而需要进行调整。 这是我现在认为是最好的select,主要是因为你可以保持内部类常量私人的类和任何其他类使用公共常量将有一个更详细的引用常量的来源(例如MyClass: :MYCONST)。 它也不会污染全局名字空间。 虽然它不利于在cpp文件中要求非整数初始化。

我也考虑过把常量放到它们自己的头文件中,并把它们包装到名字空间中,以防其他类需要常量,而不是整个类的定义。

只是寻找意见和其他可能的select,我还没有考虑。

声明一个非整型常量作为一个静态类成员的声明“不利于在cpp文件中进行非整数初始化”并不是完全可靠的,可以这么说。 它确实需要在cpp文件中定义,但这不是一个“损害”,这是你的意图的问题。 C ++中的名称空间级别的const对象默认具有内部链接,这意味着在您的原始变体中声明

 const string MyStrConst = "String"; 

相当于

 static const string MyStrConst = "String"; 

即它将在包含这个头文件的每个翻译单元中定义一个独立的MyStrConst对象。 你知道吗? 这是你的意图吗?

在任何情况下,如果您在每个翻译单元中都不需要单独的对象,那么在原始示例中MyStrConst常量的声明不是一个好习惯。 通常,你只能在头文件中放置一个非定义的声明

 extern const string MyStrConst; 

并在cpp文件中提供一个定义

 const string MyStrConst = "String"; 

从而确保整个程序使用相同的常量对象。 换句话说,当涉及非整型常量时,通常的做法是在cpp文件中定义它们。 所以,无论你如何声明(在课堂上或课堂外),你通常都必须处理必须在cpp文件中定义它的“不利因素”。 当然,正如我上面所说的,使用名称空间常量,您可以忽略第一个变体中的内容,但这只是“延迟编码”的一个示例。

无论如何,我认为没有理由把问题过分复杂化:如果常数对class级有明显的“依恋”,就应该宣布为class级成员。

PS访问说明符( publicprotectedprivate )不能控制名称的可见性 。 他们只控制其可访问性 。 名字在任何情况下都是可见的。

全局名称空间的污染是不好的,因为某人(例如,您使用的库的作者)可能希望将MyConst的名称用于其他目的。 这会导致严重的问题(不能一起使用的库等)

你的第二个解决scheme显然是最好的,如果常量链接到一个类。 如果这不是那么容易的话(考虑物理常数或math常量而不与程序中的类绑定),那么命名空间解决scheme比这更好。 顺便说一句:如果你必须与旧的C ++编译器兼容,记得其中的一些不能在头文件中使用整型初始化 – 你必须在C ++文件中初始化或在这种情况下使用旧的enum技巧。

我认为常量没有更好的select – 至less现在不能想到一个…

污染全球命名空间应该是显而易见的。 如果我包含一个头文件,我不想遇到或debugging与该头中声明的常量的名称冲突。 这些types的错误真的令人沮丧,有时很难诊断。 例如,我曾经连接过一个在头文件中定义的项目:

 #define read _read 

如果你的常量是命名空间污染,这是命名空间核废料。 这种performance是一系列非常奇怪的编译器错误,抱怨错过了_read函数,但是只有在链接到这个库时。 我们最终将读取的function重新命名为别的东西,这并不困难,但应该是不必要的。

你的第二个解决scheme是非常合理的,因为它把variables放到了范围内 没有理由,这必须与一个类相关联,如果我需要在类之间共享常量,我会在自己的名称空间和头文件中声明常量。 这对于编译时并不好,但有时候这是必要的。

我也看到有人把常量放到自己的类中,可以作为一个单例来实现。 这对我来说似乎没有奖励的工作,语言为您提供了一些声明常量的设施。

我个人使用第二种方法; 我用了好几年了,对我来说效果很好。

从可见性的angular度来看,我倾向于使私有常量文件级静态,因为实现文件之外的任何人都不需要知道它们的存在; 这有助于防止连锁反应重新编译,如果您需要更改其名称或添加新的名称范围是相同的使用范围…

只要在头文件中没有引用它们,就可以在c ++文件中声明它们为全局variables。 然后他们对这个类是私有的,不会污染全局的命名空间。

如果只有一个类将使用这些常量,请在类体内声明它们为static const 。 如果一堆相关的类将要使用这些常量,那么可以在只包含常量和实用程序方法的类/结构中声明它们,或者在专用的命名空间中声明它们。 例如,

 namespace MyAppAudioConstants { //declare constants here } 

如果它们是整个应用程序使用的常量(或其大量的块),则将它们声明在包含(无论是隐式地还是显式地)包含在任何地方的标题中的名称空间中。

 namespace MyAppGlobalConstants { //declare constants here } 

不污染全球名称空间,污染本地。

 namespace Space { const int Pint; class Class {}; }; 

但实际上…

 class Class { static int Bar() {return 357;} };