数组大小的静态常量成员

7

MyClass.h

class MyClass
{
public:

static const int cTotalCars;

private:

int m_Cars[cTotalCars];
};

MyClass.cpp

#include "MyClass.h"
const int MyClass::cTotalCars = 5;

上述代码无法工作,因为m_Cars数组会显示“预期常量表达式”。
class MyClass
{
public:

static const int cTotalCars = 5;

private:

int m_Cars[cTotalCars];
};

上述方法可行,但我听说应该在CPP文件中,在类定义之外定义静态成员。我该怎么办?

5个回答

7

简单类型的静态常量成员是该规则的一个例外,因此您后来的代码是正确的。

这个例外是比较新的(来自C++98,但直到几年后才被每个编译器实现),因此许多老式的教师还没有意识到它。他们更喜欢以下用法:

class MyClass
{
public:
   enum { cTotalCars = 5 };

private:
    int m_Cars[cTotalCars];
};

这与现在的情况完全一样,但现在看来毫无意义。


2
"简单类型的静态常量成员是该规则的例外" 是不正确的。你可能是指整数而不是简单,但即使对于整数常量,如果按照语言要求它被用作左值(大致意味着它的地址被获取),你仍然必须定义静态成员。考虑下面这个需要该定义的简单示例:void f(const int &);f(MyClass::cTotalCars); - David Rodríguez - dribeas
我之前的代码存在的问题是,当我更改值并重新构建后,其他类访问时它不会被更新。它们仍然具有旧值。进行干净的重建可以解决问题,但我不确定原因。如果我使用之前的代码,我有数组问题,但在没有进行干净构建的情况下从外部类访问时该值会被更新。 - user987280
@DavidRodríguez-dribeas 您对于积分的看法是正确的。GCC也允许使用float,但我没有注意到这是一个扩展。至于将变量用作_lvalue_,您当然也是正确的。 - rodrigo
@user987280 但这是你的编译系统存在的问题,它没有正确检查头文件的依赖性。如果你更改一个内联函数或枚举值,同样也会发生这种情况。 - rodrigo

3

以上方法可行,但据我所知,应该总是在CPP文件中,在类定义之外定义静态成员。我该怎么做呢?

好的,按照建议,您需要在CPP文件中定义静态成员。请注意,即使已经声明了值,上面的代码中静态成员仍然没有被定义。适当的最终代码应该如下所示:

// .h (ignoring all but the static member)
class MyClass {
   static const int cTotalCars = 5;        // declaration and initialization
};
// .cpp
static const int MyClass::cTotalCars;      // definition (cannot have value!)

在 .cpp 文件中的定义实际上是在将变量用作 左值 时分配空间。为了进行一个简单的测试来验证,如果没有这行代码,变量将不会被定义,您可以执行以下操作:

void f( const int & x ) {}
int main() {
   f( MyClass::cTotalCars );
}

如果在.cpp文件中没有这行代码,上面的代码将会触发链接错误,指向缺失MyClass::cTotalCars定义。代码的问题在于它“使用”静态常量成员(根据标准中“使用”的定义),这要求成员被定义。虽然使用常量来定义数组大小并不构成使用。


谢谢提供这些信息。我不需要获取此变量的地址或将其用作引用,但了解这一点很好。我更感兴趣的是我刚才在回复Rodrigo的帖子中描述的问题,即在使用我的后面的代码进行重建后,值未能更新的问题。 - user987280
@user987280:你的问题不在于语言,而是在于你的构建系统。依赖关系在你的代码库中没有正确设置,因此并非所有应该重新构建的内容都被重新构建了。花时间修复构建系统,并确保所有依赖关系正确。 - David Rodríguez - dribeas
我不确定我理解了。您要寻找哪种类型的依赖关系?您能举个例子来描述一下吗? - user987280
如果在头文件中更改常量没有触发重新构建使用该常量的所有代码,那么问题就在于构建系统没有跟踪使用依赖于头文件(否则这些将自动重新编译),这是您应该解决的问题。 - David Rodríguez - dribeas
哦,好的,我明白你的意思。除了查看VS构建设置之外,我不知道如何修复它,但是我在那里没有看到任何东西。我刚刚在另一个cpp文件的另一个类中复制了这种行为,所以至少它是一致的。 - user987280

0

我宁愿使用 #define C_TOTAL_CARS 5,然后使用 static const int cTotalCars = C_TOTAL_CARS;,并且还要使用 int m_Cars[C_TOTAL_CARS];


2
为什么要放弃作用域的好处却没有任何收益呢? - GManNickG
@Geoffroy 如果它能工作,那么它就回答了“我能做什么?”这个问题,从而回答了这个问题。现在,我的C++可能非常老式(正如GMan所暗示的:D) - Romain
你的解决方案可行,但问题是关于静态成员的。而且原帖的作者已经给出了一个可行的解决方案 :) - Geoffroy
@Geoffroy 这不是我理解问题的方式。现在,我越读越同意你的看法... :) - Romain

0
如果它是一个"static int",你需要将它放入.cpp文件中。在这种情况下,你不需要关键字"static",因为你只需要一个常量。只需使用"const int cTotalCars = 5;"。它比"#define"更好,因为你有类型信息,并且它有一个可以在调试器中查看的符号。

0

如果你在cpp文件中定义了数组的大小,它就无法工作。所有的类客户端都应该知道类实例的大小,但他们对.cpp文件一无所知,因为你只在客户端文件中包含了#include "MyClass.h"。

换句话说,你的类定义取决于不同的cpp文件,而编译使用MyClass的文件时,这些cpp文件是没有被使用的。


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