Подтвердить что ты не робот

Может ли класс перечислимого класса С++ иметь методы?

У меня есть класс enum с двумя значениями, и я хочу создать метод, который получает значение и возвращает другую. Я также хочу сохранить безопасность типов (поэтому я использую класс enum вместо перечислений).

http://www.cplusplus.com/doc/tutorial/other_data_types/ ничего не упоминает о методах Однако у меня создалось впечатление, что любой тип класса может иметь методы.

4b9b3361

Ответ 1

Нет, они не могут.

Я могу понять, что часть enum class для строго типизированных перечислений в С++ 11 может показаться, что ваше enum имеет черты class, но это не так. Мое обоснованное предположение состоит в том, что выбор ключевых слов был основан на шаблоне, который мы использовали до С++ 11 для получения перечислений с определенными областями видимости:

class Foo {
public:
  enum {BAR, BAZ};
};

Однако это всего лишь синтаксис. И снова, enum class - это не class.

Ответ 2

Хотя ответ "вы не можете" технически верен, я полагаю, что вы, возможно, сможете достичь желаемого поведения, используя следующую идею:

Я представляю, что вы хотите написать что-то вроде:

Fruit f = Fruit::Strawberry;
f.IsYellow();

И вы надеялись, что код выглядит примерно так:

enum class Fruit : uint8_t
{
  Apple, 
  Pear,
  Banana,
  Strawberry,

  bool IsYellow() { return this == Banana; }
};

...

Но, конечно, это не работает, потому что у перечислений не может быть методов (и "это" ничего не значит в приведенном выше контексте)

Однако, если вы используете идею обычного класса, содержащего перечисление, не относящееся к классу, и одну переменную-член, которая содержит значение этого типа, вы можете быть очень близки к необходимой безопасности синтаксиса/поведения/типа. то есть:

class Fruit
{
public:
  enum Value : uint8_t
  {
    Apple,
    Pear,
    Banana,
    Strawberry
  };

  Fruit() = default;
  constexpr Fruit(Value aFruit) : value(aFruit) { }

#if Enable switch(fruit) use case:
  operator Value() const { return value; }  // Allow switch and comparisons.
                                            // note: Putting constexpr here causes
                                            // clang to stop warning on incomplete
                                            // case handling.
  explicit operator bool() = delete;        // Prevent usage: if(fruit)
#else
  constexpr operator==(Fruit a) const { return value == a.value; }
  constexpr operator!=(Fruit a) const { return value != a.value; }
#endif

  constexpr bool IsYellow() const { return value == Banana; }

private:
  Value value;
};

Теперь вы можете написать:

Fruit f = Fruit::Strawberry;
f.IsYellow();

И компилятор предотвратит такие вещи, как:

Fruit f = 1;  // Compile time error.

Вы можете легко добавить такие методы, которые:

Fruit f("Apple");

а также

f.ToString();

может быть поддержано.

Ответ 3

Сосредоточив внимание на описании вопроса, а не на названии, можно ответить на вопрос

struct LowLevelMouseEvent {
    enum Enum {
        mouse_event_uninitialized = -2000000000, // generate crash if try to use it uninitialized.
        mouse_event_unknown = 0,
        mouse_event_unimplemented,
        mouse_event_unnecessary,
        mouse_event_move,
        mouse_event_left_down,
        mouse_event_left_up,
        mouse_event_right_down,
        mouse_event_right_up,
        mouse_event_middle_down,
        mouse_event_middle_up,
        mouse_event_wheel
    };
    static const char* ToStr (const type::LowLevelMouseEvent::Enum& event)
    {
        switch (event) {
            case mouse_event_unknown:         return "unknown";
            case mouse_event_unimplemented:   return "unimplemented";
            case mouse_event_unnecessary:     return "unnecessary";
            case mouse_event_move:            return "move";
            case mouse_event_left_down:       return "left down";
            case mouse_event_left_up:         return "left up";
            case mouse_event_right_down:      return "right down";
            case mouse_event_right_up:        return "right up";
            case mouse_event_middle_down:     return "middle down";
            case mouse_event_middle_up:       return "middle up";
            case mouse_event_wheel:           return "wheel";
            default:
                Assert (false);
                break;
        }
        return "";
    }
};

Ответ 4

Как уже упоминалось в другом ответе, нет. Даже enum class не является классом.


Обычно требуется иметь методы для enum, потому что это не регулярное (просто увеличивающееся) перечисление, а вид поразрядного определения значений, которые нужно маскировать, или нужен другой бит -арифметические операции:

enum class Flags : unsigned char {
    Flag1 = 0x01 , // Bit #0
    Flag2 = 0x02 , // Bit #1
    Flag3 = 0x04 , // Bit #3
    // aso ...
}

// Sets both lower bits
unsigned char flags = (unsigned char)(Flags::Flag1 | Flags::Flag2);

// Set Flag3
flags |= Flags::Flag3;

// Reset Flag2
flags &= ~Flags::Flag2;

Очевидно, каждый думает о том, чтобы инкапсулировать необходимые операции для повторного набора/группировки битов, например, битовая маска или даже операции с битовым индексом были бы полезны для манипулирования таким набором "флагов".

struct/class спецификация просто поддерживает лучшее определение значений перечисления для доступа. Не больше, не меньше!

Способы выйти из ограничения, которое вы не можете объявить методы для перечисления (классов), либо использовать std::bitset (класс оболочки) или битполе union.

union s, и такие объединения битовых полей могут иметь методы (см. здесь для ограничений!).

У меня есть образец, как преобразовать значения битовой маски (как показано выше) в соответствующие им битовые индексы, которые можно использовать по std::bitset здесь: BitIndexConverter.hpp
Я нашел это довольно полезным для повышения удобочитаемости некоторых алгоритмов, основанных на определении "флаг".

Ответ 5

Существует довольно совместимая возможность (§) реорганизовать перечисление в класс без необходимости переписывать ваш код, что означает, что вы можете эффективно выполнять то, что вы просили, без слишком большого редактирования.

(§) как указывает ElementW в комментарии, зависимый от type_traits код работать не будет, поэтому, например, нельзя использовать auto и т.д. Может быть какой-то способ обработки таких вещей, но в итоге можно преобразовать перечисление в класс, и это всегда ошибка подорвать C++

спецификации enum struct и enum class относятся к области видимости, поэтому не являются частью этого.

Ваше оригинальное перечисление, например, "домашнее животное" (это только для примера!).

enum pet { 
    fish, cat, dog, bird, rabbit, other 
};

(1) Вы изменяете это, например, на petEnum (чтобы скрыть его от существующего кода).

enum petEnum { 
    fish, cat, dog, bird, rabbit, other 
};

(2) Вы добавляете новое объявление класса под ним (названное с оригинальным перечислением)

class pet {
    private:
        petEnum value;
        pet() {}

    public:
        pet(const petEnum& v) : value{v} {} //not explicit here.
        operator petEnum() const { return value; }
        pet& operator=(petEnum v) { value = v; return *this;}
        bool operator==(const petEnum v) const { return value == v; }
        bool operator!=(const petEnum v) const { return value != v; }
 //     operator std::string() const;

};

(3) Теперь вы можете добавлять любые классовые методы, которые вам нравятся, в ваш класс питомца например. оператор строки

    pet::operator std::string() const {
        switch (value) {
            case fish: return "fish";
            case cat:  return "cat";
            case dog:  return "dog";
            case bird: return "bird";
            case rabbit: return "rabbit";
            case other: return "Wow. How exotic of you!";
        }
    }

Теперь вы можете использовать, например, std :: cout...

int main() {
    pet myPet = rabbit;
    if(myPet != fish) {
        cout << "No splashing! ";
    }
    std::cout << "I have a " << std::string(myPet) << std::endl;
    return 0;
}

Ответ 6

@jtlim Мне жаль, что это не сработает для меня

constexpr Fruit(Value aFruit) : fruit(aFruit) { }

Я получаю предупреждение и ошибку:

W: Use of this statement in a constexpr constructor is a C++14 extension
E: Constexpr constructor must initialize all members