如何检查类中已定义的枚举类型变量是否被赋值?

8

我想检查一个类中的变量是否已设置,如何实现?

enum Color {
   red,
   blue
};
class example {
   Color c;
   void set_color(Color c) { this->c = c; }
   Color get_color() { return c; }
   bool check_color_is_set() {
       if (c == Color) {} // compile error
       if (c == NULL) {} // compile error
       return true;
   }

我想知道变量 Color c 是否被赋值了?

3
不可能。与其他一些语言不同,未初始化的变量将具有“不确定”的值(几乎随机),即使只是用来检查它们的值,也会导致未定义行为 - Some programmer dude
4
你应该在枚举中定义一个“未知”的备选项,并将其设置为“c”的默认值。 - ADreNaLiNe-DJ
2
如果您想确保c始终具有有效值,则需要在构造函数中初始化c - Some programmer dude
6
我感觉你遇到了一个 XY 问题,如果你的类有一个合适的构造函数,你的问题就不会存在了。那么,你真正想要解决的问题是什么? - 463035818_is_not_a_number
2
为了更加清楚地说明,类的目的不是编写getter和setter。如果您需要调用setter来将对象带入有效状态,则做错了某些事情。另一方面,如果“no_color”是有效状态,则应使用std :: optional或将“no_color”添加到枚举中。 - 463035818_is_not_a_number
显示剩余5条评论
3个回答

7

除了具有未分配值(如@code707的答案中所述)之外,您还可以做一些事情。

相同方法,用户可以使用未初始化的类 - 缓解措施

所有这些都是基于存储布尔值,如果用户正确调用set,则可以使用。

使用您的get / set封装来检查是否已设置:

class example {
private:
    Color color;
    bool isColourSet = false;

public:
    Color get_color() const;

    void set_color(Color newCol) {
       color = newCol;
       isColourSet = true;
    }
...

然后您可以根据需要以不同的方式使用此布尔值:

抛出异常

    Color get_color() const {
       if (!isColourSet) throw some_exception; // It wasnt Set!! Throw
       return color;
    }

这种方式可以避免多余的枚举元素,同时通过抛出异常来防止返回未定义的值。


返回错误代码

如果你不想抛出异常,可以传递一个返回参数并返回一个错误码:

ErrInt get_colour(Colour &out) const {
    if (!isColourSet) return STANDARD_ERROR_VAL;
    out = color;
    return STANDARD_SUCCESS_VALUE;
}

这与枚举中的“坏值”(Bad Value)概念非常相似。


使用std::optional

自以来,您还可以使用一种新的方法std::optional,其中您可以选择性地返回(而不是引发异常或返回错误值)。

class example {
public:
    std::optional<Color> get_colour() {
        return color;
    }
    void set_color(Color newColor) {
        color = newColor;
    }
private:
    std::optional<Color> color;
}

然后用户可以像这样使用它:
auto myColor = myExample.get_colour();
if (myColour) { // Here you can check the optional
    myColour.get() // Do something with colour.
...

新的方法,用户无法将类设置为错误状态 - 重新设计

与设置一个值并且必须检查它是否正确相比,也许您可以设计这个类,使其永远不会处于无效状态。让我们看看如何做到这一点:

1. 类型安全

我们不希望用户能够设置我们不知道的任意颜色值。在当前实现中,enum 将是可以使用任何 int 值设置的类型!当某人执行 set_color(538) 时,这意味着什么?我们可以通过 c++11 的 enum class 来解决这个问题:

enum class Color {
    RED,
    BLUE
}

// This now causes a compiler error:
set_color(523);
// You can only use it like this:
set_color(Color::Red);

2个构造函数参数

我们可以通过提供一个只需要颜色参数的构造函数来强制用户选择初始颜色:

class example {
public:
    example(Color startColor) : color(startColor) {}        
...
private:
    Color c;
}

这意味着用户在创建类时必须指定一个初始颜色。现在,如果用户想要更改颜色,我们可以添加set函数:
void change_color(Color newColor) {
    color = newColor;
}

3 结论

现在您已经拥有了一个类,用户永远不会陷入无效的情况。我相信这比试图检测用户是否出错创建类要好得多。


你可以提到 std::optional - YSC
@YSC 是的,我仍在追赶有趣的C++17内容。 - Fantastic Mr Fox
请注意,虽然使用 std::optional 的强大功能,但我会将可选项作为成员变量而不是颜色+布尔值的组合。 - YSC
@YSC 是的,但是我的另一个答案才是更好的解决方案。我也会更新这个答案。 - Fantastic Mr Fox

4

是否可以为"未分配"设置特殊值?

enum Color {
   nocolor,
   red,
   blue
};
class example {
   Color c = nocolor;
   void set_color(Color c) { this->c = c; }
   Color get_color() { return c; }
   bool check_color_is_set() {
       if (c == nocolor) {} 

       return true;
   }

一个空(起始)值范式! - Swift - Friday Pie
1
你可以使用enum class Color {...}来消除隐式转换。 - user1810087

2

如果您不介意使用boost库,那么也许您可以使用boost::optional来实现。

#include <boost/optional.hpp>

enum Color {
   red,
   blue
};

class example 
{
   boost::optional<Color> c;
   void set_color(Color c) { this->c = c; }
   Color get_color() { return c; }
   bool check_color_is_set()
   {
     if( c ){
       // color is set
       return true;
     }
     else
     {
       // color is not set.
       return false;
     }
   }
}
boost::optional<Color> c的默认值是boost::none。您可以对其进行普通的 if 检查,以查看是否已经设置了某些东西。

这里是Boost Optional的文档供您参考。

注意:我没有使用STL版本的optional,但如果您不想使用Boost,您也可以随时使用std::optional


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