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
};
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
};
Odpowiedzi:
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;
};
Colorsinstancji klas. Używasz tylko wartości int w statycznych składowych stałych.
Color, tak jak w przypadku enum.
#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;
}
int basic(EnumBase b) { return b; }i int derived(EnumDeriv d) { return d; }te typy nie będą konwertowane na int, 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 intbezproblemowe użycie tej klasy posiadacza w kodzie zamiast wyliczenia.
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.
extendsjest 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;
}
BaseEnum::ipubliczne i BaseEnum::maxIprywatne.
Cóż, jeśli zdefiniujesz enumtę samą nazwę w klasie pochodnej i zaczniesz ją od ostatniego elementu korespondenta enumw 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,
};
};
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ąc Mykola Golubyevodpowiedź:
typedef struct
{
enum
{
ONE = 1,
TWO,
LAST
};
}BaseEnum;
typedef struct : public BaseEnum
{
enum
{
THREE = BaseEnum::LAST,
FOUR,
FIVE
};
}DerivedEnum;
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
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:
OriginalType myOriginalType = (OriginalType)ExtendOriginalType::EXTENDED_BAR;
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;
}
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];