基本枚举类继承


79

有没有一种模式可以让我从C ++中的另一个枚举继承?

像这样:

enum eBase 
{
   one=1, two, three
};


enum eDerived: public eBase
{
   four=4, five, six
};

Answers:


67

不可能。枚举没有继承。

您可以改为使用具有命名const ints的类。

例:

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;
};

这个解决方案有什么问题吗?例如,(我对多态性没有深刻的理解)是否可以使用vector <Colors>并使用p = std :: find(mycolors,mycolor + length,Colors :: ORANGE);?
jespestana

1
@jespestana不,您不会使用Colors类实例。您只能在静态const成员中使用int值。
jiandingzhe 2015年

如果我理解你的权利,然后,我将不得不使用vector <Int>容器。但是我仍然可以写:p = std :: find(mycolors,mycolor + length,Colors :: ORANGE);。对?
jespestana 2015年

1
绝对是@jespestana。另外,如果搜索是非常常见的操作,请考虑使用flat_set或开放地址哈希集。
v.oddou

1
回复:这个解决方案有问题吗?可能是有问题的,这些数值都没有的独特的类型的更长。您无法编写一个期望使用a的函数Color,就像您可能需要一个enum
德鲁·多曼

93
#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;
}

1
我糊涂了!然后,您将如何在变量或函数参数中引用Enum类型,又如何确保未给期望Enum的函数提供EnumDeriv?
杂耍节目Bob

20
这行不通。当您定义某些函数int basic(EnumBase b) { return b; }和时int derived(EnumDeriv d) { return d; },这些类型将不能转换为int,尽管普通枚举是。当您尝试像这样的简单代码时:cout << basic(EnumBase::One) << endl;,那么您将得到一个错误:conversion from ‘EnumBase::<anonymous enum>’ to non-scalar type ‘EnumBase’ requested。可以通过添加一些转换运算符来克服这些问题。
SasQ 2012年

10

您不能直接这样做,但是您可以尝试使用解决方案文章。

主要思想是使用保存枚举值并具有类型转换运算符的帮助程序模板类。考虑到枚举的基础类型是int您可以在代码中无缝使用此holder类,而不是枚举。


尽管此代码段可以解决问题,但提供说明确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。
NathanOliver

这是一个很好的答案。这是“以不同的方式思考问题”的例子之一,使用模板的想法确实很合适。
丹·杰森

也看看一些解决方案,这种面对面的人模板:stackoverflow.com/questions/5871722/...
田园贾森-

5

不幸的是,这在C ++ 14中是不可能的。希望我们在C ++ 17中具有这样的语言功能。由于您对于问题的解决方法很少,因此我将不提供解决方案。

我想指出,措辞应是“扩展”而不是“继承”。该扩展允许更多的值(在您的示例中,从3个值跳转到6个值),而继承意味着给给定的基类更多的约束,从而减少了可能性。因此,潜在的转换将与继承完全相反。您可以将派生类强制转换为基类,而不能将其继承为类继承。但是,在具有扩展名时,您“应该”能够将基类强制转换为其扩展名,而不是相反。我说“应该”是因为,正如我所说的那样,这种语言功能仍然不存在。


请注意,这extends是Eiffel语言中用于继承的关键字。
干杯和健康。-Alf 2015年

您说对了,因为在这种情况下,不遵守《里斯科夫替代原则》。因此,comitee将不接受语法上看起来像继承的解决方案。
v.oddou

4

这个怎么样?可以为每个可能的值创建一个实例,但是除此之外,它还非常灵活。有没有缺点?

。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;

用法:

BaseEnum e = DerivedEnum::THREE;

if (e == DerivedEnum::THREE) {
    std::cerr << "equal" << std::endl;
}

我可以看到的唯一缺点是更高的内存消耗,并且需要更多的代码行。但我会尝试您的解决方案。
Knitschi'1

我还BaseEnum::i公开和BaseEnum::maxI私有。
Knitschi

当枚举需要在需要默认构造函数的第三方宏或模板中使用时,受保护的默认构造函数可能会成为问题。
Knitschi'1

3

好吧,如果您enum在派生类中使用相同的名称进行定义,并从enum基类中的通讯员的最后一项开始,则将收到几乎所有想要的内容-继承的枚举。看下面的代码:

class Base
{
public:
    enum ErrorType
    {
        GeneralError,
        NoMemory,
        FileNotFound,
        LastItem,
    };
};

class Inherited: public Base
{
public:
    enum ErrorType
    {
        SocketError = Base::LastItem,
        NotEnoughBandwidth,
    };
};

1
虽然代码是可编译的,但是您将无法使用它,因为编译器将无法从base :: ErrorType转换为Inherited :: ErrorType。
bavaza 2011年

1
@bavaza,当然,在将其值作为参数传递时,应使用整数而不是枚举。
Haspemulator 2011年

2

如所述bayda,枚举不(和/或不应该)具有功能,因此我通过调整Mykola Golubyev的响应采取了以下方法来解决您的难题:

typedef struct
{
    enum
    {
        ONE = 1,
        TWO,
        LAST
    };
}BaseEnum;

typedef struct : public BaseEnum
{
    enum
    {
        THREE = BaseEnum::LAST,
        FOUR,
        FIVE
    };
}DerivedEnum;

2
该解决方案几乎没有问题。首先,您正在使用LAST污染BaseEnum,而LAST除了设置DerivedEnum的起点外,实际上并没有。其次,如果我想在BaseEnum中明确设置一些会与DerivedEnum值冲突的值怎么办?无论如何,就C ++ 14而言,这可能是我们所能做到的最好的选择。
ОгњенШобајић

如我所述,它是从先前的示例改编而来的,因此它是表示完整性的方式,我不担心先前的发布者在其示例中存在逻辑问题
警惕2015年

2

您可以使用项目SuperEnum创建可扩展的枚举。

/*** 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

1
虽然是老文章,但我觉得这是应该回答的。我建议摆脱默认构造函数,并将显式构造函数移至private。您仍然可以按照自己的方式初始化变量。当然,您应该摆脱const int&简单的问题int
Moia

2

有点hacky,但这是我在处理范围枚举时想到的:

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
};

然后像这样使用:

OriginalType myOriginalType = (OriginalType)ExtendOriginalType::EXTENDED_BAR;

0

不可能。
但是您可以在类中匿名定义枚举,然后在派生类中添加其他枚举常量。


0

此答案是Brian R. Bondy答案的变体。由于已在评论中被请求,因此我将其添加为答案。我并不是要指出是否真的值得。

#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;
}

住在科利鲁


-2
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;
}

用法:

std::string s1 = mamap()[ONE];
std::string s4 = mymap()[FOUR];
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.