Использование перечисления в виде индекса массива

У меня есть это перечисление:

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] для получения цветов для любого состояния, в котором находится кнопка.

Мои вопросы:

  • Это хороший стиль программирования? Есть ли лучший способ сделать это? (Обычно я использую только перечисления с операторами switch... использование перечисления как индекса массива не кажется правильным.)
  • Нужно ли указывать значения перечисления? Кажется, он начинается с 0 по умолчанию и увеличивается на 1, но гарантировано ли это работать во всех компиляторах?

Ответ 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.

Использование перечисления как индекса массива не кажется правильным.

Это хорошо. Просто ДОКУМЕНТ, поэтому следующий парень знает, что происходит! (Для чего нужны комментарии.)

Нужно ли указывать значения перечисления?

Без назначения '=', перечисление должно начинаться с нуля и увеличиваться вверх.

Если запись перечисления имеет присвоенное значение '=', последующие записи без '=' перечисляются оттуда.

Источник: справочное руководство Annotated С++, стр. 113

Тем не менее, мне нравится указывать начальное значение, чтобы сделать код намного понятнее.

Ответ 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 в качестве стартового значения (а не для ПК, но некоторые компиляторы для микроконтроллеров имеют какое-то странное поведение). Кроме того, вы можете избавиться от const:

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

Ответ 4

Вопрос 1: Я думаю, что это хороший стиль программирования. Я использую это все время. Вопрос 2: Насколько я знаю, гарантируется, что он будет работать таким образом, поэтому вам не нужно указывать значения.

И я бы поместил NUM_BUTTON_STATES в перечисление.

Ответ 5

По стилю, это просто отлично.

Языки на основе Pascal, такие как Delphi, позволяют определять границы массива как тип перечисления, поэтому вы можете использовать только элементы этого конкретного типа в качестве индекса.

Ответ 6

Совершенно нормально использовать перечисление для индексирования в массив.

Вам не нужно указывать каждое значение перечисления, они будут автоматически увеличиваться на 1. Предоставление компилятору данных значений уменьшает вероятность ошибок и создания ошибки, но это лишает вас возможности видеть значения, которые могут быть полезны в отладке.

Ответ 7

Это нормально, но я бы хотел сделать некоторые проверки границ в массиве, как если бы кто-то добавил еще одну ButtonState, у вас возникнет проблема.

Кроме того, элементы массива цветов неизменяемы, поэтому, возможно, посмотрите на использование другой коллекции для массива, чтобы вы могли обеспечить ее неизменность. Возможно, Dictionary<ButtonState,ButtonColor>