【问题标题】:Using an enum as an array index使用枚举作为数组索引
【发布时间】:2010-09-29 02:06:26
【问题描述】:

我有这个枚举:

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 递增,但它是否保证在所有编译器中都以这种方式工作?

【问题讨论】:

    标签: c++ enums


    【解决方案1】:

    这是好的编程风格吗?

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

    有更好的方法吗?

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

    缺点是 NUMBER_OF_BUTTON_STATES 现在是一个有效的 Button::State 值。如果您将这些值作为 ints 传递,这不是什么大问题。但是如果你真的期待一个Button::State,那就麻烦了。

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

    没关系。只需DOCUMENT它,让下一个人知道发生了什么! (这就是 cmets 的用途。)

    我必须指定枚举的值吗?

    如果没有 '=' 赋值,枚举的应该从零开始并向上递增。

    如果枚举条目具有“=”赋值,则后续非“=”枚举条目从那里继续计数。

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

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

    【讨论】:

    • 您应该使用命名空间而不是空类。它更准确地符合您的意图。
    • C 和 C++ 语言标准指定枚举中的第一个枚举常量的值为零,除非您为其分配不同的值。任何不这样做的编译器显然都是不合规的。
    • ChrisN 是对的,但遗憾的是,我曾使用过这样的编译器——而且在过去的 10 年中,同样如此。如果您对交叉编译器兼容性有任何顾虑,请指定零。
    • 根据 OP,类将有成员 ButtonState 和 ButtonColors。我把它们放在一边是为了避免分散注意力。
    • 在之前的工作中,我为不同的目标使用了三种不同的编译器,所以我可能记错了——但我相信它是 Green Hills C++ 编译器的特定版本。如果未设置,第一个值可以是任何值;基本上就好像编译器对第一个值使用了一个未初始化的变量。
    【解决方案2】:

    是的,它会很好用。也就是说,无论如何,您真的应该在枚举中添加另一个条目来定义项目数量的值:

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

    然后你可以像这样定义数组

    Color colors[STATE_COUNT];
    

    否则,将状态数量与数组大小保持同步会很麻烦。如果没有以其他方式初始化,枚举将始终从零开始,然后每个附加条目将被分配一个比前一个条目高一的值,如果没有以其他方式初始化。当然,如果你愿意的话,如果你明确地输入一个零也不会受到伤害。如果您不介意额外的代码,我会使用类似的函数来包装对原始数组的访问

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

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

    【讨论】:

      【解决方案3】:

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

      enum ButtonState {
          BUTTON_NORMAL = 0,
          BUTTON_PRESSED,
          BUTTON_CLICKED,
          NUM_BUTTON_STATES
      };
      

      【讨论】:

      • 您实际上是在说“您不应该假设编译器执行标准要求他们执行的操作”,这从根本上来说并不是一个坏建议。除非另有说明,否则标准要求 enums 从 0 开始,程序员不应羞于利用这一点 - 或寻找称职的编译器。
      【解决方案4】:

      风格方面,这很好。

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

      【讨论】:

        【解决方案5】:

        问题1:我认为这是一种很好的编程风格。我用它所有的时间。 问题 2:据我所知,它可以保证以这种方式工作,因此您不必指定值。

        我也会将 NUM_BUTTON_STATES 放入枚举中。

        【讨论】:

          【解决方案6】:

          使用枚举来索引数组是完全正常的。

          您不必指定每个枚举值,它们会自动递增 1。让编译器选择这些值可以减少错误输入和产生错误的可能性,但它会让您无法看到这些值,这可能很有用正在调试中。

          【讨论】:

            【解决方案7】:

            没关系,但我想对数组做一些边界检查,好像有人添加了另一个 ButtonState,你会遇到问题。

            此外,colors 数组的元素是不可变的,因此可以考虑使用不同的集合来数组,这样您就可以强制实现这种不变性。也许是Dictionary<ButtonState,ButtonColor>

            【讨论】:

            • 谁说数组不能是不可变的?而且 C++ 没有称为 Dictionary 的标准容器;也许你的意思是map。不过,对于大多数使用简单且连续的数字“键”的情况,我看不到这一点。充其量,它避免了用户必须强制/记住索引顺序,但这样做是在查找速度的权衡。
            猜你喜欢
            • 2016-06-26
            • 2010-11-02
            • 1970-01-01
            • 2019-11-17
            • 1970-01-01
            • 2022-08-15
            • 2012-03-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多