总之
在您的课程Txtbin 中,将 const 定义为静态:
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 设置不同的值。
告诉编译器的正确方法是使这个常量static。这使得常量独立于类的任何对象。然后,您可以在任何需要的地方仅使用Txtbin::ERR_EMPTY_IMAGE 引用它。
一旦它是静态的,您还可以在switch 中继续使用a.ERR_EMPTY_IMAGE,因为编译器会发现它不需要非常量对象a 来确定值。
还要注意,对象的大小也会更小,因为不需要在每个实例中都复制静态值。
为什么这里 const 不够用?
您可以很好地拥有一个公共const,该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 会更好吗?
constexpr 是告诉编译器您希望表达式在编译时保持不变的方式。所以你可以在case 中使用这种表达方式。
现在由于上述所有原因,constexpr 无论如何都要求您的成员变量为static:
public:
constexpr static int ERR_EMPTY_IMAGE = 2;
在您的情况下,constexpr 的主要优点是更快地突出任何误解。因为你很可能像这样定义你的成员
public:
const static int ERR_EMPTY_IMAGE;
并在类外初始化它的值。这使得它非常棘手。从语义上讲,对于 C++,这仍然是一个静态常量(即它的值永远不会改变)。并且在初始化常量的编译单元中,由于常量传播,它将被用作编译时常量。但在其他编译单元中,它的值在编译时是未知的(它可能只有在链接时才知道)。
使用constexpr 而不是const,编译器会立即抱怨声明中缺少初始化。所以使用它可能是一个优势,至少如果你不必使用一些旧的编译器。