102

Is there a pattern where I can inherit enum from another enum in C++??

Something like that:

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


enum eDerived: public eBase
{
   four=4, five, six
};
Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108

14 Answers14

104
#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;
}
Mykola Golubyev
  • 57,943
  • 15
  • 89
  • 102
  • 3
    I'm confused! How would you then refer to the Enum types in a variable or function argument, and how would you ensure that a function expecting Enum wasn't given an EnumDeriv? – Sideshow Bob Nov 29 '11 at 14:12
  • 26
    This won't work. When you define some functions `int basic(EnumBase b) { return b; }` and `int derived(EnumDeriv d) { return d; }`, those types won't be convertible to `int`, although plain enums are. And when you try even such simple code like this one: `cout << basic(EnumBase::One) << endl;`, then you'll get an error: `conversion from ‘EnumBase::’ to non-scalar type ‘EnumBase’ requested`. Those problems may probably be overcomed by adding some conversion operators. – SasQ Dec 12 '12 at 01:30
74

Not possible. There is no inheritance with enums.

You can instead use classes with named const ints.

Example:

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;
};
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • Is there any problem with this solution? For example, (I don't have deep understanding of Polymorphism) Would it be possible to have a vector and use, p = std::find (mycolors,mycolor+length,Colors::ORANGE);? – jespestana Jun 12 '13 at 01:38
  • 2
    @jespestana No, you won't use `Colors` class instances. You only use the int values in the static const members. – jiandingzhe Jan 20 '15 at 02:43
  • If I understand you right; then, I would have to use a vector container. But I would still be able to write: p = std::find (mycolors,mycolor+length,Colors::ORANGE);. right? – jespestana Jan 21 '15 at 07:28
  • 1
    @jespestana absolutely. also if searching is a very common operation, consider using a flat_set or an open address hash set. – v.oddou Jun 22 '16 at 03:12
  • 3
    Re: _Is there any problem with this solution?_ It **could be** problematic that these values are no longer of a distinct type. You could not write a function that expects a `Color`, like you could for an `enum`. – Drew Dormann Oct 15 '17 at 04:11
  • @DrewDormann if instead of `static const int RED` it becomes a `static const Colors RED` initializing the variable e putting the int value to a private field he could do that – Moia Jul 26 '18 at 07:14
  • @Moia - your comment was over a year ago but any chance you can elaborate? if he does `static const Colors RED` then what is the enclosing class called? I'm trying to do something similar to OP and wondered about your workaround. –  Dec 12 '19 at 11:40
  • @BithikaMookherjee i made an answer with that right now – Moia Dec 13 '19 at 09:36
  • 2
    You'd better make those values 'constexpr' rather than 'const'. – Red.Wave Mar 11 '20 at 20:16
  • Did this change with the new `enum class`? The term `class` looks more like it can be inherited. (IMHO: no it doesn't change anything, the `class` just moves them into a named type so they need to be accessed with a scope operator or whatever you call that thing before `::`) – Thomas Weller Mar 07 '23 at 07:00
12

You can't do that directly, but you could try to use solution from this article.

The main idea is to use the helper template class which holds enum values and has the type cast operator. Considering that the underlying type for enum is int you can use this holder class seamlessly in your code instead of the enum.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
  • 1
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-‌​code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – NathanOliver Feb 12 '16 at 14:00
  • This is a great answer; it's one of those instances of "think about the problem a different way" and the idea of using a template really fits the bill. – Den-Jason Aug 11 '17 at 11:05
  • Also take a look at some of the solutions to this vis-a-vis templates: https://stackoverflow.com/questions/5871722/how-to-achieve-virtual-template-function-in-c – Den-Jason Aug 11 '17 at 11:29
5

Unfortunately it is not possible in C++14. I hope we will have such a language feature in C++17. As you already got few workarounds for your problem I won't provide a solution.

I would like to point out that the wording should be "extension" not "inheritance". The extension allows for more values (as you're jumping from 3 to 6 values in your example) whereas inheritance means putting more constraints to a given base class so the set of possibilities shrinks. Therefore, potential casting would work exactly opposite from inheritance. You can cast derived class to the base class and not vice-verse with class inheritance. But when having extensions you "should" be able to cast the base class to its extension and not vice-verse. I am saying "should" because, as I said such a language feature still doesn't exist.

  • Note that `extends` is a keyword for inheritance in the Eiffel language. – Cheers and hth. - Alf Jun 28 '15 at 03:30
  • You are right because in this case the Liskov Substitution Principle is not respected. The comitee will not accept a solution that looks like inheritance syntaxically because of this. – v.oddou Jun 22 '16 at 03:16
4

How about this? Ok an instance is created for every possible value, but besides that its very flexible. Are there any downsides?

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

Usage:

BaseEnum e = DerivedEnum::THREE;

if (e == DerivedEnum::THREE) {
    std::cerr << "equal" << std::endl;
}
D-rk
  • 5,513
  • 1
  • 37
  • 55
  • The only disadvantages that I can see are the higher memory consumtion and that it needs more lines of code. But I will try your solution. – Knitschi Jan 11 '17 at 07:12
  • I also made ````BaseEnum::i```` public and ````BaseEnum::maxI```` private. – Knitschi Jan 11 '17 at 07:31
  • The protected default constructor can be a problem when the enum needs to be used in 3rd party macros or templates that require a default constructor. – Knitschi Jan 12 '17 at 15:17
3

You can use a project SuperEnum to create extendable enumerations.

/*** 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
    Though is an old post, I feel this deserve an answer. I would suggest to get rid of the default constructor and move the explicit constructor to private. You can still init the variable in the way you're doing. Of course you should get rid of the `const int&` for a simple `int` – Moia Jul 26 '18 at 07:09
2

As stated by bayda, enum's don't (and/or shouldn't) have functionality, so I've taken the following approach to your quandary by adapting Mykola Golubyev's response:

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

typedef struct : public BaseEnum
{
    enum
    {
        THREE = BaseEnum::LAST,
        FOUR,
        FIVE
    };
}DerivedEnum;
vigilance
  • 116
  • 1
  • 11
  • 2
    There are few problems with this solution. First, you are polluting BaseEnum with LAST which doesn't really exist other than to set the starting point for DerivedEnum. Second, what if I want to explicitely set some values in BaseEnum which would collide with DerivedEnum values? Anyways, that's probably the best we can do so far as in C++14. – Огњен Шобајић Sep 18 '14 at 21:54
  • Like I stated, it's adapted from a previous example, so it is expressed the way it is for completeness, it is not my concern that the previous poster has logical issues in their example – vigilance Jun 04 '15 at 20:49
2

Well, if you'll define enum with the same name in derived class and start it from last item of correspondent enum in base class, you'll receive almost what you want - inherited enum. Look at this code:

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

class Inherited: public Base
{
public:
    enum ErrorType
    {
        SocketError = Base::LastItem,
        NotEnoughBandwidth,
    };
};
ceztko
  • 14,736
  • 5
  • 58
  • 73
Haspemulator
  • 11,050
  • 9
  • 49
  • 76
  • 1
    while the code is compilable, you won't be able to use it, as the compiler won't be able to convert from base::ErrorType to Inherited::ErrorType. – bavaza Feb 27 '11 at 14:27
  • 1
    @bavaza, sure, you should use integer instead of enums when passing their values as parameters. – Haspemulator Mar 03 '11 at 08:41
2

Kind of hacky but this is what I came up with if dealing with scoped enums:

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

and then use like:

OriginalType myOriginalType = (OriginalType)ExtendOriginalType::EXTENDED_BAR;
jsadler
  • 109
  • 6
2

This answer is a variant of Brian R. Bondy answer. Since has been requested in a comment I'm adding it as answer. I'm not pointing about if it really worths though.

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

Live at Coliru

Moia
  • 2,216
  • 1
  • 12
  • 34
1

Impossible.
But you can define the enum anonymously in a class, then add additional enum constants in derived classes.

NmdMystery
  • 2,778
  • 3
  • 32
  • 60
bayda
  • 13,365
  • 8
  • 39
  • 48
1

My Solution is similar to some above, except that I wanted to return in my functions like an enum (constructor that takes the STATUS_ENUM value), and compare like an enum (operators that compare the STATUS_ENUM value to the class). I also wanted a clean way of using the base class without having to cast and check things (operator override). Lastly I wanted to make sure that only the type I specify can construct the class (deleted template).

        struct StatusReturn
        {
            /**
             * Use this to communicate trigger conditions internally to the caller.
             * - Extend this class with a child who adds more static const STATUS_ENUM values as options.
             * - When checking the return simply compare with != or == and the class will handle the rest.
             *   - This is true for a base class and a derived value, since this base class holds the value.
             */

            typedef int STATUS_ENUM;

            StatusReturn() = delete;
            
            template <typename T>
            StatusReturn(T) = delete;
            StatusReturn(STATUS_ENUM value): _value(value) {};

            // Operator overloads to compare the int to the class
            friend bool operator==(const StatusReturn & lhs, const STATUS_ENUM & rhs)
            { return lhs.getValue() == rhs; };
            friend bool operator!=(const StatusReturn & lhs, const STATUS_ENUM & rhs)
            { return !(lhs == rhs); };
            friend bool operator==(const STATUS_ENUM & lhs, const StatusReturn & rhs)
            { return lhs == rhs.getValue(); };
            friend bool operator!=(const STATUS_ENUM & lhs, const StatusReturn & rhs)
            { return !(lhs == rhs); };

            // Non-exit triggering return
            static const STATUS_ENUM CONTINUE = -1;

            // Exit triggering values
            static const STATUS_ENUM FAILED = 0;
            static const STATUS_ENUM SUCCESS = 1;
            static const STATUS_ENUM HALTED = 2;

            STATUS_ENUM getValue() const
            { return _value; };

        protected:
            STATUS_ENUM _value = CONTINUE;
        };

Some examples of use:

        StatusReturn shouldExit()
        {
            return successBool ? StatusReturn::SUCCESS : StatusReturn::CONTINUE;
        }

Which when called looks like:

        auto exitValue = shouldExit();
        if (exitValue != StatusReturn::CONTINUE)
        {
            return exitValue;
        }

Then a check of a derived class is as such:

        auto exitValue = shouldExit();
        if (exitValue != DerivedReturn::DO_STUFF)
        {
            return exitValue;
        }

Here, since DO_STUFF is also a STATUS_ENUM type, the operators just work without any explicit casting.

Ian A McElhenny
  • 910
  • 8
  • 20
0

You can do this in c++ 20 by Using-enum-declaration

enum eBase 
{
   one=1, two, three
};
enum eExtension
{
   four=4, five, six
};
struct eDerived {
    using enum eBase;
    using enum eExtension;
}

Unfortunately, eDerived is not enum type, so you cannot initialize an object of eDerived as enum does eDerived g = eDerived::one;. Also, you have to manage enumeration the initial value of eExtension.

But, something like this will work

int g = eDerived::one;
switch(g){
case eDerived::one: break;
case eDerived::five: break;
}
mr NAE
  • 3,144
  • 1
  • 15
  • 35
-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;
}

Usage:

std::string s1 = mymap()[ONE];
std::string s4 = mymap()[FOUR];
Konrad Kleine
  • 4,275
  • 3
  • 27
  • 35