¿Hay un patrón en el que pueda heredar la enumeración de otra enumeración en C ++?
Algo como eso:
enum eBase
{
one=1, two, three
};
enum eDerived: public eBase
{
four=4, five, six
};
Imposible. No hay herencia con enumeraciones.
En su lugar, puede usar clases con constantes con nombre.
Ejemplo:
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
instancias de clase. Solo usa los valores int en los miembros estáticos const.Color
, como podría hacerlo para unenum
.#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; }
fuente
int basic(EnumBase b) { return b; }
yint derived(EnumDeriv d) { return d; }
, esos tipos no serán convertibles aint
, aunque las enumeraciones simples sí lo son. Y cuando intenta incluso como simple código como éste:cout << basic(EnumBase::One) << endl;
, entonces obtendrá un error:conversion from ‘EnumBase::<anonymous enum>’ to non-scalar type ‘EnumBase’ requested
. Es probable que estos problemas se solucionen agregando algunos operadores de conversión.No puede hacer eso directamente, pero puede intentar usar la solución de este artículo.
La idea principal es usar la clase de plantilla auxiliar que contiene valores de enumeración y tiene el operador de conversión de tipos. Teniendo en cuenta que el tipo subyacente de enum es
int
que puede usar esta clase de titular sin problemas en su código en lugar de la enumeración.fuente
Desafortunadamente, no es posible en C ++ 14. Espero que tengamos una característica de lenguaje de este tipo en C ++ 17. Como ya tiene algunas soluciones para su problema, no proporcionaré una solución.
Me gustaría señalar que la redacción debería ser "extensión" y no "herencia". La extensión permite más valores (ya que está saltando de 3 a 6 valores en su ejemplo) mientras que la herencia significa poner más restricciones a una clase base determinada para que el conjunto de posibilidades se reduzca. Por lo tanto, el casting potencial funcionaría exactamente de manera opuesta a la herencia. Puede convertir la clase derivada a la clase base y no viceversa con la herencia de clases. Pero al tener extensiones, "debería" poder convertir la clase base en su extensión y no al revés. Digo "debería" porque, como dije, tal característica de lenguaje todavía no existe.
fuente
extends
es una palabra clave para herencia en el idioma Eiffel.¿Qué tal esto? Ok, se crea una instancia para cada valor posible, pero además de eso es muy flexible. ¿Hay alguna desventaja?
.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;
Uso:
BaseEnum e = DerivedEnum::THREE; if (e == DerivedEnum::THREE) { std::cerr << "equal" << std::endl; }
fuente
BaseEnum::i
público yBaseEnum::maxI
privado.Bueno, si lo define
enum
con el mismo nombre en la clase derivada y lo inicia desde el último elemento correspondienteenum
en la clase base, recibirá casi lo que desea: enumeración heredada. Mira este código:class Base { public: enum ErrorType { GeneralError, NoMemory, FileNotFound, LastItem, }; }; class Inherited: public Base { public: enum ErrorType { SocketError = Base::LastItem, NotEnoughBandwidth, }; };
fuente
Como se indica en
bayda
, las enumeraciones no tienen (y / o no deberían) tener funcionalidad, por lo que he adoptado el siguiente enfoque para su dilema adaptandoMykola Golubyev
la respuesta:typedef struct { enum { ONE = 1, TWO, LAST }; }BaseEnum; typedef struct : public BaseEnum { enum { THREE = BaseEnum::LAST, FOUR, FIVE }; }DerivedEnum;
fuente
Puede utilizar un proyecto SuperEnum para crear enumeraciones extensibles.
/*** 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
fuente
const int&
por un simpleint
Un poco hacky, pero esto es lo que se me ocurrió si estaba tratando con enumeraciones con ámbito:
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 };
y luego usa like:
fuente
Esta respuesta es una variante de la respuesta de Brian R. Bondy. Dado que se ha solicitado en un comentario, lo agrego como respuesta. Sin embargo, no estoy señalando si realmente vale la pena.
#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; }
Vivir en Coliru
fuente
Imposible.
Pero puede definir la enumeración de forma anónima en una clase y luego agregar constantes de enumeración adicionales en las clases derivadas.
fuente
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; }
Uso:
std::string s1 = mamap()[ONE]; std::string s4 = mymap()[FOUR];
fuente