Есть ли способ в С++ расширять/ "наследовать" перечисления?
то есть:
enum Enum {A,B,C};
enum EnumEx : public Enum {D,E,F};
или, по крайней мере, определить преобразование между ними?
Есть ли способ в С++ расширять/ "наследовать" перечисления?
то есть:
enum Enum {A,B,C};
enum EnumEx : public Enum {D,E,F};
или, по крайней мере, определить преобразование между ними?
Нет, нет.
enum
действительно бедны в С++, и это, к сожалению, конечно.
Даже class enum
, введенный в С++ 0x, не затрагивает эту проблему расширяемости (хотя они делают некоторые вещи для безопасности типа, по крайней мере).
Единственное преимущество enum
заключается в том, что они не существуют: они предлагают некоторую безопасность типов, не налагая накладные расходы во время выполнения, поскольку они напрямую заменяются компилятором.
Если вы хотите такого зверя, вам придется самому работать:
MyEnum
, содержащий int (в основном)теперь вы можете расширить свой класс (добавив именованные конструкторы) по желанию...
Что-то обходное решение, я никогда не нашел способ улавливания ссылок на перечисление...
Если вам удалось создать подкласс перечисления, ему пришлось бы работать наоборот.
Набор экземпляров в подклассе является подмножеством экземпляров в суперклассе. Подумайте о стандартном примере "Shape". Класс Shape представляет набор всех Shapes. Класс Circle, его подкласс, представляет собой подмножество Shapes, которые являются кругами.
Итак, чтобы быть последовательным, подкласс перечисления должен был содержать подмножество элементов в перечислении, которое он наследует.
(И нет, С++ не поддерживает это.)
Я решил так:
typedef enum
{
#include "NetProtocols.def"
} eNetProtocols, eNP;
Конечно, если вы добавите новый сетевой протокол в файл NetProtocols.def, вам придется перекомпилировать, но, по крайней мере, его можно расширить.
http://www.codeproject.com/KB/cpp/InheritEnum.aspx переходит метод для создания расширенного перечисления.
Просто идея:
Вы можете попытаться создать пустой класс для каждой константы (возможно, поместить их все в один файл, чтобы уменьшить беспорядок), создать один экземпляр каждого класса и использовать указатели для этих экземпляров как "константы". Таким образом, компилятор поймет наследование и выполнит любое преобразование ChildPointer-to-ParentPointer, необходимое при использовании вызовов функций, и вы все равно получите проверки безопасности типа компилятором, чтобы гарантировать, что никто не передает недопустимое значение int для функций (что для использования, если вы используете метод LAST value для "расширения" перечисления).
Не все это до конца додумалось, хотя любые замечания по этому подходу приветствуются.
И я попытаюсь опубликовать пример того, что я имею в виду, когда у меня есть время.
Я пробовал это, он работает, но это немного утомительно:
#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;
}
Следующий код работает хорошо.
enum Enum {A,B,C};
enum EnumEx {D=C+1,E,F};