正确理解如何处理C++类常量

22

考虑以下内容:

namespace MyNamespace{
class MyClass {
public:
   // Public area
private:
   // Private area
protected:
   // Protected area
}; /* Class */
} /* Namespace */

考虑到我想要为我的类定义一个特定的常量。通常我会这样做:

namespace MyNamespace{
// Constants
const int MYINT = 12;
const std::string MYSTR = std::string("Hello");
// Class definition
class MyClass {
public:
   // Public area
private:
   // Private area
protected:
   // Protected area
}; /* Class */
} /* Namespace */

这样我就可以在代码的某处通过这种方式获取我的变量:

MyNamespace::MYINT;
MyNamespace::MYSTR;

这是好的编程实践吗? 考虑到常量可以通过多种方式来处理(例如,数字常量通常使用枚举来处理),那么定义一个常量(与类相关,但也可能在其他地方有用)的最佳方法是什么?

谢谢


删除所有元标签(那些实际上并不涉及问题的标签)和冗长的“分类”开头。只需提出您的问题,不需要所有的礼节性用语。这样可以让其他人更容易地阅读您的问题。 - jalf
不需要道歉。 :) 只需记住,提问的目标是要清晰易懂。这意味着它应该仅包含必要的信息,并立即进入主题。我们知道这是一个C++问题,因为它被标记为这样(而且在标题中),所以没有必要在问题的前三行告诉我们同样的事情。而且我们知道这是关于最佳实践的,因为没有人会问关于最差实践的问题。这里的每个问题都是关于的做法。 ;) - jalf
2个回答

40
如果你想要类特定的常量,并且希望它们在其他地方也能有用途,如你所说,可能是在类外部,那么请将它们定义为类的 public 部分中的 static 成员数据:
//.h file
class MyClass 
{
 public:
   //constants declarations
   static const int MYINT;
   static const std::string MYSTR;
};

//.cpp file
//constants definitions 
const int MyClass::MYINT = 12;
const std::string MyClass::MYSTR = std::string("Hello");

用法(或访问):

std::cout << MyClass::MYINT << std::endl;
std::cout << MyClass::MYSTR << std::endl;

输出:

12
Hello

在线演示:http://www.ideone.com/2xJsy


如果你想定义许多整数常量并且它们都有某种相关性,也可以使用enum,例如:

class shirt
{
 public:
   //constants declarations
   enum shirt_size
   {
        small, 
        medium,
        large,
        extra_large
   };
};

但是如果整数常量之间没有关联,那么据我所见,将它们定义为enum就没有太多意义了。


@Andry: 不可以的。你需要在头文件中声明它们,并在单独的.cpp文件中定义它们。 - Jon
1
@Andry:不行,如果你这样做,当你在许多cpp文件中包含头文件时,会出现多重定义错误。因此,最好的方法是:定义应该在.cpp文件中,就像我编辑我的答案一样。 - Nawaz
3
可以简短回答“不行”,但是如果常量是整数类型,则可以在头文件中仅声明并分配该值。需要注意的是,只有当整数常量没有被“使用”时才可以这样做,“使用”的意思是“用作左值”。也就是说,你可以将其用作编译时常量或在任何需要rvalue的情况下使用:int x = 1 + type::constant;,但不能在需要lvalue的情况下使用:int const & k = type::constant; - David Rodríguez - dribeas
@Nawaz:对于整型常量,通常最好在声明中提供值,而不是在定义中。这使编译器能够将该值用作编译时常量。 struct test { static const int a = 5; static const int b; }; int const test :: a; int const test :: b = 7; int array [test :: a]; / *好的* / int error [test :: b]; / *不好的* / - David Rodríguez - dribeas
@David Rodríguez:不错。我通常这样做。现在我没有这样做,因为还有const std::string,我无法在类本身中初始化它。所以为了保持一致性,我这样做了。 :-) - Nawaz

5

当然,“最佳”解决方案是非常主观的,因此并不存在“最佳”解决方案。

考虑到您提到这些常量在其他地方被使用,我们可以说它们应该在类的protected(如果它们只能由派生类使用)或更可能是public部分中声明。

非整数类型的常量应定义为static const成员(但如果有任何其他静态对象引用这些常量,则必须注意静态初始化的顺序)。

整数类型的常量可以声明为static const int或枚举类型,正如您已经提到的。这里的区别在于两个或多个常量是否可以逻辑上组合在一起。

例如,这可能是一个好主意:

class MyClass {
    public:
        enum {
            Color_Red,
            Color_Green,
            Color_Blue,
        };
};

虽然这不是:

class MyClass {
    public:
        enum {
            Color_Red,
            Vehicle_Car,
        };
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接