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

Расширение перечислений на С++?

Есть ли способ в С++ расширять/ "наследовать" перечисления?

то есть:

enum Enum {A,B,C};
enum EnumEx : public Enum {D,E,F};

или, по крайней мере, определить преобразование между ними?

4b9b3361

Ответ 1

Нет, нет.

enum действительно бедны в С++, и это, к сожалению, конечно.

Даже class enum, введенный в С++ 0x, не затрагивает эту проблему расширяемости (хотя они делают некоторые вещи для безопасности типа, по крайней мере).

Единственное преимущество enum заключается в том, что они не существуют: они предлагают некоторую безопасность типов, не налагая накладные расходы во время выполнения, поскольку они напрямую заменяются компилятором.

Если вы хотите такого зверя, вам придется самому работать:

  • создать класс MyEnum, содержащий int (в основном)
  • создавать именованные конструкторы для каждого из интересных значений

теперь вы можете расширить свой класс (добавив именованные конструкторы) по желанию...

Что-то обходное решение, я никогда не нашел способ улавливания ссылок на перечисление...

Ответ 2

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

Набор экземпляров в подклассе является подмножеством экземпляров в суперклассе. Подумайте о стандартном примере "Shape". Класс Shape представляет набор всех Shapes. Класс Circle, его подкласс, представляет собой подмножество Shapes, которые являются кругами.

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

(И нет, С++ не поддерживает это.)

Ответ 3

Я решил так:

typedef enum
{
    #include "NetProtocols.def"
} eNetProtocols, eNP;

Конечно, если вы добавите новый сетевой протокол в файл NetProtocols.def, вам придется перекомпилировать, но, по крайней мере, его можно расширить.

Ответ 5

Просто идея:

Вы можете попытаться создать пустой класс для каждой константы (возможно, поместить их все в один файл, чтобы уменьшить беспорядок), создать один экземпляр каждого класса и использовать указатели для этих экземпляров как "константы". Таким образом, компилятор поймет наследование и выполнит любое преобразование ChildPointer-to-ParentPointer, необходимое при использовании вызовов функций, и вы все равно получите проверки безопасности типа компилятором, чтобы гарантировать, что никто не передает недопустимое значение int для функций (что для использования, если вы используете метод LAST value для "расширения" перечисления).

Не все это до конца додумалось, хотя любые замечания по этому подходу приветствуются.

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

Ответ 6

Я пробовал это, он работает, но это немного утомительно:

#include <iostream>

struct Foo {
protected:
  int _v;
  Foo(int i) : _v(i) {}

public:
  operator int() const { return _v; }

  static Foo FOO() { return 5; };
};

struct Bar : public Foo {
  using Foo::Foo;
  Bar(const Foo &f) : Foo(f) {}

  static Bar BAR() { return 6; };
};

int main(int argc, const char *argv[]) {
  // Bar bar = Bar::BAR();
  Foo foo = Foo::FOO();
  Bar bar = Bar::BAR();

  // 5
  Bar b = foo;
  std::cout << (int)b << std::endl;

  // 6
  b = bar;
  std::cout << (int)b << std::endl;

  // 5
  b = foo;
  std::cout << (int)b << std::endl;

  // Foo err1(5);
  // Bar err2(5);
  return 0;
}

Ответ 7

Следующий код работает хорошо.

enum Enum {A,B,C};
enum EnumEx {D=C+1,E,F};