如何从对象获取公共常量? [重复]

问题描述 投票:-1回答:1

这个问题在这里已有答案:

当我这样做

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;
c++ class switch-statement const
1个回答
0
投票

简而言之

在你的类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;
}

很长一段时间,有了所有的解释

Why static ?

实际上,初始化常量的方式清楚地表明它并不特定于任何对象:您不打算在类的两个对象中为ERR_EMPTY_IMAGE设置不同的值。

告诉编译器的正确方法是使这个const static。这使得常量独立于类的任何对象。然后,您可以在任何地方使用Txtbin::ERR_EMPTY_IMAGE来引用它。

一旦它是静态的,你也可以继续在a.ERR_EMPTY_IMAGE中使用switch,因为编译器会发现它不需要非const对象a来确定值。

另请注意,对象的大小也会更小,因为静态值不需要在每个实例中重复。

Why is const not sufficient here ?

你可以很好地拥有一个公共的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

Would constexpr be even better ?

constexpr是对编译器说你希望表达式在编译时是常量的方式。所以你可以在case中使用的那种表达方式。

现在由于上面解释的所有原因,constexpr无论如何都要求你的成员变量是static

public:
    constexpr static int ERR_EMPTY_IMAGE   = 2;   

在你的情况下,constexpr的主要优势是更快地突出任何误解。因为您可以很好地将您的成员定义为这样

public:
    const static int ERR_EMPTY_IMAGE; 

并在课堂外初始化其值。这使得它非常棘手。从语义上讲,对于C ++,这仍然是一个静态常量(即它的值永远不会改变)。在初始化常量的编译单元中,由于常量传播,它将被用作编译时常量。但是在其他编译单元中,其值在编译时是未知的(可能仅在链接时才知道)。

使用constexpr而不是const,编译器会立即通过告诉您声明中缺少初始化来抱怨。所以使用它可能是一个优点,至少如果你不必使用一些旧的编译器。

© www.soinside.com 2019 - 2024. All rights reserved.