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

时间:2010-01-11 17:18:01

标签: c++ constants declaration

我很好奇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";

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

我还考虑将常量移动到自己的头文件中并将它们包装在命名空间中,以防其他类需要常量,但不是整个类定义。

只是在寻找意见和其他我尚未考虑的选项。

7 个答案:

答案 0 :(得分:45)

你声称将非整数常量声明为静态类成员“不利于要求在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文件中定义它的“损害”。当然,正如我上面所说,使用命名空间常量,你可以放弃第一个变体中的内容,但这只是“懒惰编码”的一个例子。

无论如何,我认为没有理由使问题过于复杂:如果常量对类具有明显的“附件”,则应将其声明为类成员。

P.S。访问说明符(publicprotectedprivate)不控制名称的可见性。他们只控制辅助功能。无论如何,这个名字仍然可见。

答案 1 :(得分:10)

全局命名空间的污染很糟糕,因为有人(例如您使用的库的编写者)可能希望将名称MyConst用于其他目的。这可能导致严重的问题(不能一起使用的库等)。

如果常量链接到单个类,那么第二个解决方案显然是最好的。如果这不是那么容易(想想物理或数学常量而没有与程序中的类相关联),命名空间解决方案就更好了。顺便说一句:如果你必须兼容旧的C ++编译器,请记住其中一些不能在头文件中使用整数初始化 - 在这种情况下,你必须在C ++文件中初始化或使用旧的enum技巧。

我认为对于常数没有更好的选择 - 至少目前还不能想到一个......

答案 2 :(得分:5)

污染全局命名空间应该是不言自明的。如果我包含头文件,我不想遇到或调试与该头中声明的常量的名称冲突。这些类型的错误确实令人沮丧,有时难以诊断。例如,我曾经不得不链接一个在标题中定义的项目:

#define read _read

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

您的第二个解决方案非常合理,因为它将变量放入范围。没有必要将它与一个类相关联,如果我需要在类之间共享常量,我将在它们自己的命名空间和头文件中声明常量。这对于编译时来说不是很好,但有时它是必要的。

我也看到人们将常量放入他们自己的类中,这可以作为单例实现。这对我来说似乎没有奖励,语言为你提供了一些声明常量的工具。

答案 3 :(得分:2)

您可以在c ++文件中将它们声明为全局变量,只要它们未在标题中引用即可。然后它们对该类是私有的,不会污染全局命名空间。

答案 4 :(得分:2)

我个人使用你的第二种方法;我已经用了很多年了,它对我很有用。

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

答案 5 :(得分:2)

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

namespace MyAppAudioConstants
{
     //declare constants here
}

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

namespace MyAppGlobalConstants
{
    //declare constants here
}

答案 6 :(得分:-1)

不污染全局命名空间,污染本地。

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

但实际上......

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