代码之家  ›  专栏  ›  技术社区  ›  Paige Ruten

使用枚举作为数组索引

  •  63
  • Paige Ruten  · 技术社区  · 17 年前

    我有这个枚举:

    enum ButtonState {
        BUTTON_NORMAL = 0,
        BUTTON_PRESSED = 1,
        BUTTON_CLICKED = 2
    };
    
    const u8 NUM_BUTTON_STATES = 3;
    

    在我的Button类中,我有成员变量 ButtonState state; 和 ButtonColors colors[NUM_BUTTON_STATES]; 。绘制按钮时,我使用 colors[state] 获取按钮所处状态的颜色。

    我的问题:

    1. 这种编程风格好吗?有更好的方法吗?(我通常只使用带有switch语句的枚举……将枚举用作数组索引感觉不对。)
    2. 我是不是 有 指定枚举的值?默认情况下,它似乎从0开始,递增1,但是否保证在所有编译器中都能以这种方式工作?
    8 回复  |  直到 17 年前
        1
  •  53
  •   Mr.Ree    17 年前

    这种编程风格好吗?

    我想是的。我经常做同样的事情。

    有更好的方法吗?

    class Button
    {
    public:
        // Used for array indexes!  Don't change the numbers!
      enum State {
        NORMAL = 0,
        PRESSED,
        CLICKED,
        NUMBER_OF_BUTTON_STATES
      };
    };
    

    缺点是 按钮状态编号 现在是有效的 按钮::状态 价值。如果你把这些值当作 整数 。但如果你真的期待一个 按钮::状态 .

    将枚举用作数组索引感觉不对。

    没事的。只是 文件 这样下一个人就知道发生了什么!(这就是评论的目的。)

    我必须指定枚举的值吗?

    没有“=”赋值,枚举 应该是 从零开始,向上递增。

    如果枚举条目分配了“=”值,则后续的非“=”枚举条目将从那里继续计数。

    来源: 带注释的C++参考手册 ,第113页

    也就是说,我喜欢指定初始值,只是为了让代码更清晰。

        2
  •  26
  •   Johannes Schaub - litb    17 年前

    是的,它会工作得很好。也就是说,不管怎样,你 真正地 应该在枚举中添加另一个条目,定义项目数量的值:

    enum ButtonState {
        BUTTON_NORMAL,
        BUTTON_PRESSED,
        BUTTON_CLICKED,
        STATE_COUNT
    };
    

    然后,您可以定义数组,如下所示

    Color colors[STATE_COUNT];
    

    否则,保持状态量与数组大小同步会很混乱。如果不进行初始化,枚举将始终从零开始,然后如果不进行其他初始化,每个额外的条目都将被分配一个比前一个高一个的值。当然,如果你愿意,如果你明确地加一个零,也不会有什么坏处。如果你不介意额外的代码,我会用一个函数来包装对原始数组的访问,比如

    Color & operator[](ButtonState state) {
        return array[state];
    }
    

    或同等产品 getColor 函数转发请求。这将禁止直接用某个整数对数组进行索引,这几乎肯定会在某个时候失败,因为索引是错误的。

        3
  •  15
  •   Stefan    17 年前

    使用枚举是可以的。但您不必为每个项目指定值。指定第一个值就足够了。我不会假设枚举从0开始,因为我使用的编译器使用1作为起始值(不适用于PC,但一些微控制器的编译器有一些奇怪的行为)。 你也可以去掉const:

    enum ButtonState {
        BUTTON_NORMAL = 0,
        BUTTON_PRESSED,
        BUTTON_CLICKED,
        NUM_BUTTON_STATES
    };
    
        4
  •  5
  •   Roddy    17 年前

    风格方面,这很好。

    基于Pascal的语言,如Delphi,允许将数组边界指定为枚举类型,因此您只能将该特定类型的项用作索引。

        5
  •  3
  •   Nathan Stoddard Nathan Stoddard    17 年前

    问题1:我认为这是一种很好的编程风格。我一直在用它。 问题2:据我所知,它保证以这种方式工作,所以你不必指定值。

    我也会将NUM_BUTTON_STATES放入枚举中。

        6
  •  1
  •   Mark Ransom    17 年前

    使用枚举对数组进行索引是完全正常的。

    您不必指定每个枚举值,它们将自动递增1。让编译器选择值可以降低键入错误和创建错误的可能性,但它会剥夺您看到值的机会,而这些值在调试中可能很有用。

        7
  •  1
  •   WOPR    17 年前

    这很好,但我想对数组进行一些边界检查,就像有人添加了另一个ButtonState一样,你会遇到问题。

    此外,colors数组的元素是不可变的,所以也许可以考虑使用不同的数组集合,这样你就可以强制执行这种不可变性。也许a Dictionary<ButtonState,ButtonColor>

        8
  •  0
  •   Sergiy Maksymenko    3 年前

    其中一种方法是在类中创建一个内部向量并重写运算符[]:( here is the link to online code )

    #include <iostream>
    #include <vector>
    
    template<typename DATA_TYPE, typename INDEX_TYPE>
    class MyVector
    {
    protected:
        std::vector<DATA_TYPE> pp;
    
    public:    
        template<typename ... ARGS>
        MyVector(ARGS ... args): pp{args...} {};
    
        DATA_TYPE& operator[](INDEX_TYPE x) { 
            return pp[static_cast<size_t>(x)];
        };
    
        auto size() const { return pp.size(); }
    
        // implement other menthods
    
    
    };
    
    enum class EWeekDays{
        SUN, MON, TUE, WED, THU, FRI, SAT
    };
    
    
    int main()
    {
        MyVector<int, EWeekDays> q{2,3,4,5};
    
        std::cout << q[EWeekDays::MON] << "\n";
    
        return 0;
    }