在类中定义常量(用于常量表达式),最佳方法是什么?

6

我正在尝试为我的类定义一个常量BUFFER_LENGTH,以适用于特定用例。

//1. Using preprocessor declaration
//#define BUFFER_LENGTH  12

//2.Global constant
//const int BUFFER_LENGTH  = 12;
class MyRequest
{
public:
    //3. Define an in-class constant
    //static const int BUFFER_LENGTH = 12;

    //4. Declare an enum constant
    enum 
    {
        BUFFER_LENGTH = 12
    };

    MyRequest()
    {
        strcpy(mBuffer, "TestString");
        printf("Buffer: %s, BUFFER_LENGTH = %d",mBuffer, BUFFER_LENGTH);
    }
private:
    char mBuffer[BUFFER_LENGTH];
};

我刚刚列出了定义类常量的不同方法。

1. Using Preprocessor constant
2. Using Global constant
3. Using in-class constant
4. using an enum.

在这些方法中,哪一种是定义给定用例的常量的最佳方法?我更喜欢使用枚举常量而不是其他方法。是否有其他更好的方法我错过了吗?

谢谢。

7个回答

10

枚举类型并不是用来定义数字常量的,尽管在模板元编程中经常被滥用为此。

如果常量的含义与类相关联,那么我会在类中定义它。那么你仍然有两个选择:

 class WithConst {
 public:

     // 1. as a const static member variable
     static const int sc_nNumber = 100; // I can initialize here for
                                        // integral-types only

     // 2. as a static member function - possibly inlined.
     static int sf_nNumber() { return 100; }
 };

第二种选择的优点是,当你想要从注册表或配置文件中读取常量时,不需要稍后修改任何客户端代码。


1
第二个示例根据当前标准的规则不是“常量整数表达式”,因此不能用作例如数组索引。 - Richard Corden
1
在static constexpr int sf_nNumber() { return 100; }成为有效的const表达式之前,您需要等待一段时间。 - Eclipse
@Josh:确实!C++0x 定义了 'constexpr' 关键字来注释这一点。(不知为何,这让我想起了什么) - xtofl

9

为了维护方便,尽可能将任何名称(无论是函数、变量还是常量)的范围限制得更小。因此,我建议采用以下方式:

static const int BUFFER_LENGTH = 12;

或者

enum { BUFFER_LENGTH = 12 };

在类定义内部。

前一种方法并没有太多好处,除了你可以明确控制类型。 enum 会导致 C++ 为你选择一个未指定的整数“基础类型” - 如果你的枚举只包含小值,它可能很小,比如 char,尽管根据经验,大多数编译器默认使用 int


3

静态常成员变量是最好的选择 - 它简洁,完全解决了问题,并保证不会与其他类似类发生冲突(这在预处理器定义或全局常量中是很可能发生的)。我建议您将其声明为CamelCase而不是全部大写带下划线,这样它看起来不像是特殊的东西,而是一个真正的普通类成员。


2

我有VC 6编译器。它不支持静态常量类成员! - aJ.

1

我不确定在这种特定情况下它们是否完全可互换。由于您基于常量来确定数组成员的大小,我认为它必须是枚举值。我没有时间在标准中查找,但即使它是static const,由于实际值可能在头文件中不可见,因此我会感到惊讶如果您可以使用int成员作为数组大小。

// === in myclass.h
class MyClass {
public:
    static const int MY_SIZE;
private:
    int ary[MY_SIZE];
};

// === in myclass.cpp
/*static*/ const int MyClass::MY_SIZE = 10;

// === in otherclass.cpp
void OtherClass::operation(MyClass& obj) {
    std::cout << "Sizeof(MyClass) = " << sizeof(obj) << std::endl;
}

我认为编译器不能在编译myclass.cpp之前编译otherclass.cpp

在大多数其他情况下,我会选择使用类静态常量选项,因为它在类型推断等方面会更聪明一些。我只在真正需要时或者当它们是真正的枚举常量时才使用枚举整数常量(当然)。

编辑

在午餐时间我看了一下标准(感谢David的提醒):

整数常量表达式只能涉及文字、枚举值、const变量或已用常量表达式初始化的整数型或枚举型静态数据成员(8.5)、整数型或枚举型非类型模板参数和sizeof表达式。

看起来常量和枚举都可以工作,只要你在声明(或定义)中提供常量初始值即可。


在标准的C++中,const int是一个编译时常量,并且可以作为这样使用。你必须在声明时进行初始化。 - David Thornley

1

使用const int可能比使用枚举(enum)效率低下,以下是一个演示程序。在Windows的Metrowerks CodeWarrior 8.x编译器下编译,它显示定义常量为const int的类的对象比定义为枚举的类多占用了4个字节的内存:

#include <stdio.h>
#include <stdlib.h>

class foo {
    enum { MY_CONST = 1 };
    int x;
    public:
    foo();
};
class bar {
    const int MY_CONST;
    int x;
    public:
    bar();
};

int main() {
    printf( "%u %u\n", sizeof( foo), sizeof( bar));
    return EXIT_SUCCESS;
}

它产生:"4 8"

构造函数被添加以防止编译器进行过度优化。因为程序不创建这些类型的对象,所以构造函数不必在单独的编译模块中实际定义。对于const int也是如此。


0
在阅读以前的帖子时,我注意到没有人提到“命名空间中的枚举”技巧。如果您喜欢枚举,因为您正在使用旧编译器(我在VxWorks / Tornado嵌入式编程平台上有这样的经验),那么请注意:您可以通过将枚举放置在命名空间内或(如果不支持命名空间)放置在类内来避免命名冲突。

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