Использование перечислений правильно C ++ - PullRequest
0 голосов
/ 27 февраля 2011

Я пытался научиться правильно использовать перечисления в C ++ и с трудом понимаю, как с ними обращаться.Я сделал простую программу, которая изменяет светофоры, используя перечисления и побитовые операции:

    #include <iostream>

enum lights
{
    green = 1,
    yellow = 2,
    red = 4,
    control = 7
};

std::string change_light (std::string choice)
{
    lights light;
    int changed;

    if (choice == "yellow")
        light = yellow;

    else if (choice == "red")
        light = red;

    else if (choice == "green")
        light = green;

    changed = control & light;

    if (changed == red)
        return "red";

    else if (changed == yellow)
        return "yellow";

    else if (changed == green)
        return "green";
}

int main()
{   
    std::string choice = "";

    while (1)
    {
        std::cout << "What light do you want to turn on?" << std::endl;
        std::cin >> choice;
        std::cout << "Changed to " << change_light(choice) << std::endl;
    }

    return 0;
}

Как мне улучшить эту программу, сохранив использование побитовых операций и перечислений?Если бы вы могли показать мне, как его улучшить, это значительно улучшило бы мое понимание того, как правильно использовать перечисления.

Спасибо: D

Ответы [ 3 ]

5 голосов
/ 27 февраля 2011

Основная идея перечислений заключается в том, что вы можете определить набор констант, которые дают пользователю и компилятору некоторые подсказки о том, как использовать переменную.

Ваш пример будет более понятным, еслиФункция change_light будет принимать аргумент lights следующим образом:

std::string change_light (lights choice)
{
    switch(choice)
    {
    case red: return "red";
    case yellow: return "yellow";
    case green: return "green";
    }
}

Таким образом, компилятор знает, что функция принимает только определенные аргументы, и вы не получаете вызовы функций, такие как change_light ("blue")

Таким образом, вы используете перечисления для защиты остальной части вашего кода от неправильных значений аргументов.Вы не можете напрямую прочитать перечисление из std :: in, так как оно ничего не знает о вашем перечислении.После прочтения вы должны преобразовать ввод в перечисление.Примерно так:

lights string_to_ligths(std::string choice)
{
    if(choice == "red") return red;
    if(choice == "yellow") return yellow;
    if(choice == "green") return green;
}

С этого момента все ваши функции, связанные со светофором, принимают только значения enum и не нужно проверять, находится ли значение запроса в допустимом диапазоне.

2 голосов
/ 27 февраля 2011

Перечисления - это просто целые числа, которые имеют ограниченные допустимые диапазоны значений.

Допустим, вы реализуете свой семафор с помощью int:

#define SEMAPHORE_STATE_RED 1
#define SEMAPHORE_STATE_YELLOW 2
#define SEMAPHORE_STATE_GREEN 3
int semaphore_state;

Следующее будет проходить очень хорошо, хотянарушает семантику вашего семафора:

semaphore_state = 10;

с перечислением, которое он не пройдет, компилятор с перехватом ошибки.

Это даже больше, если вы будете использовать switch вместо if /еще:

switch (state)
{
    case SEMAPHORE_STATE_GREEN: /* bla */ break;
    case SEMAPHORE_STATE_RED: /* bla */ break;
    /* if state would be enum, compiler would catch that we are missing the SEMAPHORE_STATE_YELLOW case */
}

Конечно, есть и другие применения перечислений.Например, я лично предпочитаю константы enum, а не define (никогда не использую сам тип enum).Этот случай также является единственным, который может сосуществовать с побитовыми операциями с большими трудностями.

1 голос
/ 12 мая 2011

Похоже, у вас есть идея, что числа, связанные с перечисляемым типом, важны.На самом деле цифры не важны вообще.Настоящая идея перечислимого типа состоит в том, чтобы аккуратно захватить переменную, которая имеет набор состояний, которые являются не числовыми и которые также будут плохо захвачены при использовании символа (например, масти игральных карт, указания компаса).или дни недели).Редко, если вообще когда-либо, присваивают конкретные числа любому из значений перечисления - это средство, которое не является частью точки перечислимого типа (но это очень редко полезно, поэтому оно сохраняется) и служит для запутыванияначинающему программисту, чем помогать, и его не следует рассматривать как неотъемлемую часть перечисления - некоторые языки этого даже не допускают (например, Modula-3, Haskell, Ocaml).Перечислимые типы используются не очень часто - их использование немного неясно, и они не часто полезны: они добавляют программе ясность, а не мощность (в отличие от, например, оператора if , без которого программирование было быпочти невозможно!) и на самом деле никогда не нужны как таковые.Это означает, что фрагмент кода, который вы написали, хотя и показывает используемый перечислимый тип, не демонстрирует свою полезность: перечисляемый тип вступает в свои права при разъяснении аспекта некоторых более крупных программ, использование которого нелегко продемонстрировать.Начинающим программистам лучше всего игнорировать их, поскольку они кажутся бессмысленными и вводящими в заблуждение новичка.Это потому, что их цель трудно продемонстрировать - хотя они полезны, я обещаю вам!Я повторяю: они предлагают ясность выражения, а не силу.

...