Czy istnieje wzorzec, w którym mogę dziedziczyć wyliczenie z innego wyliczenia w C ++?
Coś w tym stylu:
enum eBase
{
one=1, two, three
};
enum eDerived: public eBase
{
four=4, five, six
};
Niemożliwe. Nie ma dziedziczenia z wyliczeniami.
Zamiast tego możesz używać klas z nazwanymi stałymi intami.
Przykład:
class Colors
{
public:
static const int RED = 1;
static const int GREEN = 2;
};
class RGB : public Colors
{
static const int BLUE = 10;
};
class FourColors : public Colors
{
public:
static const int ORANGE = 100;
static const int PURPLE = 101;
};
Colors
instancji klas. Używasz tylko wartości int w statycznych składowych stałych.Color
, tak jak w przypadkuenum
.#include <iostream> #include <ostream> class Enum { public: enum { One = 1, Two, Last }; }; class EnumDeriv : public Enum { public: enum { Three = Enum::Last, Four, Five }; }; int main() { std::cout << EnumDeriv::One << std::endl; std::cout << EnumDeriv::Four << std::endl; return 0; }
źródło
int basic(EnumBase b) { return b; }
iint derived(EnumDeriv d) { return d; }
te typy nie będą konwertowane naint
, chociaż zwykłe wyliczenia są. I podczas próby nawet takiego kodu proste jak ten:cout << basic(EnumBase::One) << endl;
Pokochasz więc pojawia się błąd:conversion from ‘EnumBase::<anonymous enum>’ to non-scalar type ‘EnumBase’ requested
. Prawdopodobnie te problemy można rozwiązać poprzez dodanie kilku operatorów konwersji.Nie możesz tego zrobić bezpośrednio, ale możesz spróbować użyć rozwiązania z tego artykułu.
Głównym pomysłem jest użycie pomocniczej klasy szablonu, która przechowuje wartości wyliczenia i ma operator rzutowania typu. Biorąc pod uwagę, że podstawowym typem wyliczenia jest
int
bezproblemowe użycie tej klasy posiadacza w kodzie zamiast wyliczenia.źródło
Niestety nie jest to możliwe w C ++ 14. Mam nadzieję, że taka funkcja języka będzie dostępna w C ++ 17. Ponieważ masz już kilka obejść swojego problemu, nie przedstawię rozwiązania.
Chciałbym zaznaczyć, że powinno brzmieć „rozszerzenie”, a nie „dziedziczenie”. Rozszerzenie pozwala na więcej wartości (jak w przykładzie przeskakujesz z 3 do 6 wartości), podczas gdy dziedziczenie oznacza nakładanie większej liczby ograniczeń na daną klasę bazową, więc zestaw możliwości się kurczy. Dlatego potencjalne rzutowanie działałoby dokładnie odwrotnie niż dziedziczenie. Możesz rzutować klasę pochodną na klasę bazową, a nie na odwrót z dziedziczeniem klas. Ale mając rozszerzenia, "powinieneś" być w stanie rzutować klasę bazową na jej rozszerzenie, a nie odwrotnie. Mówię „powinienem”, ponieważ, jak powiedziałem, taka funkcja języka nadal nie istnieje.
źródło
extends
jest to słowo kluczowe określające dziedziczenie w języku Eiffla.Co powiesz na to? Ok, instancja jest tworzona dla każdej możliwej wartości, ale poza tym jest bardzo elastyczna. Czy są jakieś wady?
.h:
class BaseEnum { public: static const BaseEnum ONE; static const BaseEnum TWO; bool operator==(const BaseEnum& other); protected: BaseEnum() : i(maxI++) {} const int i; static int maxI; }; class DerivedEnum : public BaseEnum { public: static const DerivedEnum THREE; };
.cpp:
int BaseEnum::maxI = 0; bool BaseEnum::operator==(const BaseEnum& other) { return i == other.i; } const BaseEnum BaseEnum::ONE; const BaseEnum BaseEnum::TWO; const DerivedEnum DerivedEnum::THREE;
Stosowanie:
BaseEnum e = DerivedEnum::THREE; if (e == DerivedEnum::THREE) { std::cerr << "equal" << std::endl; }
źródło
BaseEnum::i
publiczne iBaseEnum::maxI
prywatne.Cóż, jeśli zdefiniujesz
enum
tę samą nazwę w klasie pochodnej i zaczniesz ją od ostatniego elementu korespondentaenum
w klasie bazowej, otrzymasz prawie to, czego chcesz - dziedziczone wyliczenie. Spójrz na ten kod:class Base { public: enum ErrorType { GeneralError, NoMemory, FileNotFound, LastItem, }; }; class Inherited: public Base { public: enum ErrorType { SocketError = Base::LastItem, NotEnoughBandwidth, }; };
źródło
Jak stwierdzono
bayda
, wyliczenia nie mają (i / lub nie powinny) mieć funkcjonalności, więc zastosowałem następujące podejście do twojego dylematu, dostosowującMykola Golubyev
odpowiedź:typedef struct { enum { ONE = 1, TWO, LAST }; }BaseEnum; typedef struct : public BaseEnum { enum { THREE = BaseEnum::LAST, FOUR, FIVE }; }DerivedEnum;
źródło
Możesz użyć projektu SuperEnum do tworzenia rozszerzalnych wyliczeń.
/*** my_enum.h ***/ class MyEnum: public SuperEnum<MyEnum> { public: MyEnum() {} explicit MyEnum(const int &value): SuperEnum(value) {} static const MyEnum element1; static const MyEnum element2; static const MyEnum element3; }; /*** my_enum.cpp ***/ const MyEnum MyEnum::element1(1); const MyEnum MyEnum::element2; const MyEnum MyEnum::element3; /*** my_enum2.h ***/ class MyEnum2: public MyEnum { public: MyEnum2() {} explicit MyEnum2(const int &value): MyEnum(value) {} static const MyEnum2 element4; static const MyEnum2 element5; }; /*** my_enum2.cpp ***/ const MyEnum2 MyEnum2::element4; const MyEnum2 MyEnum2::element5; /*** main.cpp ***/ std::cout << MyEnum2::element3; // Output: 3
źródło
const int&
się prostegoint
Trochę hacky, ale oto, co wymyśliłem, jeśli mam do czynienia z wyliczeniami o określonym zakresie:
enum class OriginalType { FOO, // 0 BAR // 1 END // 2 }; enum class ExtendOriginalType : std::underlying_type_t<OriginalType> { EXTENDED_FOO = static_cast<std::underlying_type_t<OriginalType>> (OriginalType::END), // 2 EXTENDED_BAR // 3 };
a następnie użyj:
źródło
Ta odpowiedź jest wariantem odpowiedzi Briana R. Bondy'ego. Ponieważ został o to poproszony w komentarzu, dodaję to jako odpowiedź. Nie wskazuję jednak, czy naprawdę warto.
#include <iostream> class Colors { public: static Colors RED; static Colors GREEN; operator int(){ return value; } operator int() const{ return value; } protected: Colors(int v) : value{v}{} private: int value; }; Colors Colors::RED{1}; Colors Colors::GREEN{2}; class RGB : public Colors { public: static RGB BLUE; private: RGB(int v) : Colors(v){} }; RGB RGB::BLUE{10}; int main () { std::cout << Colors::RED << " " << RGB::RED << std::endl; }
Mieszkaj w Coliru
źródło
Niemożliwy.
Ale można zdefiniować wyliczenie anonimowo w klasie, a następnie dodać dodatkowe stałe wyliczenia w klasach pochodnych.
źródło
enum xx { ONE = 1, TWO, xx_Done }; enum yy { THREE = xx_Done, FOUR, }; typedef int myenum; static map<myenum,string>& mymap() { static map<myenum,string> statmap; statmap[ONE] = "One"; statmap[TWO] = "Two"; statmap[THREE] = "Three"; statmap[FOUR] = "Four"; return statmap; }
Stosowanie:
std::string s1 = mamap()[ONE]; std::string s4 = mymap()[FOUR];
źródło