Gibt es ein Muster, in dem ich eine Aufzählung von einer anderen Aufzählung in C ++ erben kann?
So ähnlich:
enum eBase
{
one=1, two, three
};
enum eDerived: public eBase
{
four=4, five, six
};
Gibt es ein Muster, in dem ich eine Aufzählung von einer anderen Aufzählung in C ++ erben kann?
So ähnlich:
enum eBase
{
one=1, two, three
};
enum eDerived: public eBase
{
four=4, five, six
};
Antworten:
Nicht möglich. Es gibt keine Vererbung mit Aufzählungen.
Sie können stattdessen Klassen mit benannten Konstanten verwenden.
Beispiel:
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
Klasseninstanzen verwenden. Sie verwenden nur die int-Werte in den statischen const-Elementen.
Color
, wie Sie es für eine könnten 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; }
und definieren int derived(EnumDeriv d) { return d; }
, können diese Typen nicht konvertiert werden int
, obwohl dies einfache Aufzählungen sind. Und wenn Sie selbst so einfachen Code wie diesen ausprobieren cout << basic(EnumBase::One) << endl;
:, erhalten Sie eine Fehlermeldung : conversion from ‘EnumBase::<anonymous enum>’ to non-scalar type ‘EnumBase’ requested
. Diese Probleme können wahrscheinlich durch Hinzufügen einiger Konvertierungsoperatoren behoben werden.
Sie können dies nicht direkt tun, aber Sie könnten versuchen, die Lösung aus diesem Artikel zu verwenden.
Die Hauptidee besteht darin, die Hilfsvorlagenklasse zu verwenden, die Enum-Werte enthält und den Operator type cast hat. Wenn man bedenkt, dass der zugrunde liegende Typ für die Aufzählung ist int
, können Sie diese Halterklasse nahtlos in Ihrem Code anstelle der Aufzählung verwenden.
Leider ist dies in C ++ 14 nicht möglich. Ich hoffe, wir werden eine solche Sprachfunktion in C ++ 17 haben. Da Sie bereits einige Problemumgehungen für Ihr Problem haben, werde ich keine Lösung anbieten.
Ich möchte darauf hinweisen, dass der Wortlaut "Erweiterung" und nicht "Vererbung" sein sollte. Die Erweiterung ermöglicht mehr Werte (da Sie in Ihrem Beispiel von 3 auf 6 Werte springen), während Vererbung bedeutet, dass einer bestimmten Basisklasse mehr Einschränkungen auferlegt werden, sodass die Anzahl der Möglichkeiten abnimmt. Daher würde potenzielles Casting genau entgegengesetzt zur Vererbung funktionieren. Sie können abgeleitete Klassen in die Basisklasse umwandeln und nicht umgekehrt mit Klassenvererbung. Wenn Sie jedoch Erweiterungen haben, sollten Sie in der Lage sein, die Basisklasse in ihre Erweiterung umzuwandeln und nicht umgekehrt. Ich sage "sollte", weil, wie gesagt, eine solche Sprachfunktion immer noch nicht existiert.
extends
ein Schlüsselwort für die Vererbung in der Eiffel-Sprache ist.
Wie wäre es damit? Ok, für jeden möglichen Wert wird eine Instanz erstellt, aber außerdem ist sie sehr flexibel. Gibt es Nachteile?
.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;
Verwendung:
BaseEnum e = DerivedEnum::THREE;
if (e == DerivedEnum::THREE) {
std::cerr << "equal" << std::endl;
}
BaseEnum::i
öffentlich und BaseEnum::maxI
privat gemacht.
Wenn Sie enum
in der abgeleiteten Klasse denselben Namen definieren und ihn vom letzten Korrespondenzelement enum
in der Basisklasse starten , erhalten Sie fast das, was Sie möchten - geerbte Aufzählung. Schauen Sie sich diesen Code an:
class Base
{
public:
enum ErrorType
{
GeneralError,
NoMemory,
FileNotFound,
LastItem,
};
};
class Inherited: public Base
{
public:
enum ErrorType
{
SocketError = Base::LastItem,
NotEnoughBandwidth,
};
};
Wie von angegeben bayda
, haben Enums keine Funktionalität (und / oder sollten es auch nicht), daher habe ich den folgenden Ansatz für Ihr Dilemma gewählt, indem ich die Mykola Golubyev
Antwort angepasst habe :
typedef struct
{
enum
{
ONE = 1,
TWO,
LAST
};
}BaseEnum;
typedef struct : public BaseEnum
{
enum
{
THREE = BaseEnum::LAST,
FOUR,
FIVE
};
}DerivedEnum;
Sie können ein Projekt SuperEnum verwenden , um erweiterbare Aufzählungen zu erstellen.
/*** 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&
für eine einfacheint
Ein bisschen hacky, aber das ist es, was ich mir ausgedacht habe, wenn ich mich mit Enums befasst habe:
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
};
und dann benutze wie:
OriginalType myOriginalType = (OriginalType)ExtendOriginalType::EXTENDED_BAR;
Diese Antwort ist eine Variante der Antwort von Brian R. Bondy. Da in einem Kommentar angefordert wurde, füge ich ihn als Antwort hinzu. Ich weise nicht darauf hin, ob es sich wirklich lohnt.
#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;
}
Verwendung:
std::string s1 = mamap()[ONE];
std::string s4 = mymap()[FOUR];