这个问题在这里已有答案:
当我这样做
Txtbin a;
switch(err){
case a.ERR_EMPTY_IMAGE:
std::cerr << "Error: Image is empty\n" << std::endl;
break;
}
我收到这个错误
txtbin.cpp:在函数'int main(int,char **)'中:txtbin.cpp:97:11:错误:'a'的值在常量表达式中不可用a.ERR_EMPTY_IMAGE:^
常量ERR_EMPTY_IMAGE
在类中定义如下:
public:
const int ERR_EMPTY_IMAGE = 2;
在你的类Txtbin
中,将const定义为static:
public:
static const int ERR_EMPTY_IMAGE = 2;
然后
switch(err){
case Txtbin::ERR_EMPTY_IMAGE:
std::cerr << "Error: Image is empty\n" << std::endl;
break;
}
实际上,初始化常量的方式清楚地表明它并不特定于任何对象:您不打算在类的两个对象中为ERR_EMPTY_IMAGE
设置不同的值。
告诉编译器的正确方法是使这个const static
。这使得常量独立于类的任何对象。然后,您可以在任何地方使用Txtbin::ERR_EMPTY_IMAGE
来引用它。
一旦它是静态的,你也可以继续在a.ERR_EMPTY_IMAGE
中使用switch
,因为编译器会发现它不需要非const对象a
来确定值。
另请注意,对象的大小也会更小,因为静态值不需要在每个实例中重复。
你可以很好地拥有一个公共的const
,它对于班级的每个对象都是不同的:
class Test2 {
public:
const int ERR_EMPTY_IMAGE;
Test2(int x) : ERR_EMPTY_IMAGE{x} {}
};
Test2 c(5), d(6);
cout << "Test2 c ->"<< c.ERR_EMPTY_IMAGE<<" d->"<< d.ERR_EMPTY_IMAGE<<endl;
const只会告诉一旦构造对象,成员的值不会改变。这就是你的编译器在第一个实例中抱怨的原因:const不足以让编译器在编译时定义它。证明:
class Test1 {
public:
const int ERR_EMPTY_IMAGE = 2;
Test1() = default; // default constructor
Test1(int x) : ERR_EMPTY_IMAGE{x} {}
};
Test1 b;
Test1 b_ouch(9);
cout << "Sizeof b: "<< sizeof(b) <<endl;
cout << "Test1 b ->"<< b.ERR_EMPTY_IMAGE<<" b_ouch->"<< b_ouch.ERR_EMPTY_IMAGE<<endl;
这里是上面所说的online demo
constexpr
是对编译器说你希望表达式在编译时是常量的方式。所以你可以在case
中使用的那种表达方式。
现在由于上面解释的所有原因,constexpr
无论如何都要求你的成员变量是static
:
public:
constexpr static int ERR_EMPTY_IMAGE = 2;
在你的情况下,constexpr
的主要优势是更快地突出任何误解。因为您可以很好地将您的成员定义为这样
public:
const static int ERR_EMPTY_IMAGE;
并在课堂外初始化其值。这使得它非常棘手。从语义上讲,对于C ++,这仍然是一个静态常量(即它的值永远不会改变)。在初始化常量的编译单元中,由于常量传播,它将被用作编译时常量。但是在其他编译单元中,其值在编译时是未知的(可能仅在链接时才知道)。
使用constexpr
而不是const
,编译器会立即通过告诉您声明中缺少初始化来抱怨。所以使用它可能是一个优点,至少如果你不必使用一些旧的编译器。