Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement something that has both enum and class behavior

Consider that I have some 'thing' that has both enum and class behavior. As an example, consider a world which has the concept of Color, there are exactly 3: Red, Green and Blue.

Based on this color, we also have functionality, for example we could have a function which tells us whether a Color is a happy Color or not, and some other functions:

isHappy: Color -> {yes, no}
intensity: Color -> value
rotate: Color -> Color

To complete the haskel-like syntax, we could do this:

data Color = Red | Green | Blue

and implement the functions mentioned above. But that is haskell, which is not C++ and which has no notion of OO like c++ has. Continuing in C++:

The fact that we have exactly 3 colors, and no more, suggest the use of an enum; allowing us to use constants like red, blue and green anywhere in the source code. However, we cannot add methods to an enum, so isHappy intensity and rotate would be implemented as functions (and not methods).

The fact that we have these methods where the first parameter is a Color, suggest the use of a class. However, then we could instantiate as many of such classes as we'd like, especially more than 3. This means that two variables representing Red, will be allocated at different locations in memory. This is a bit strange, as Red will have very 'constant-like' behavior since it is immutable and only three different types of Color objects can be created. Moreover, we cannot use symbols like Red, Green and Blue, but would need to store them in variables. Using global variables would be very ugly imho.

We could also use inheritance, where Red, Green and Blue inherit from a Color class. This allows us to fine tune the functionality very easily, since we can implement what we want in whatever class we want. However, OO with inheritance in c++ applies slicing. For example, it would be very tricky to create a vector containing a list of (Red, Green or Blue)'s. Or to create a variable storing one of the 3 colors:

Color c1 = Red();
Color c2 = Blue();

The variables c1 and c2 will be assigned a different object, but there is no way to really distinct them. This makes implementing operator== tricky:

class Red : Color { //...
  bool operator==(Color &c) const{
     // no way to determine whether c is Red, Green or Blue.
  }
}

Is there a valid pattern or solution for this situation? I think it appears a lot, hence I am very curious. C++14-only solutions are also very much appreciated!

EDIT: Many people seem to comment that the problems for the solutions that I mention are not really problems. That is a valid point. However, I'm not looking for a possible solution, I'm looking for a solution which is according to a good c++(11|14) design principles. I could also use:

#define RED 0
#define GREEN 1
#define BLUE 2

And that would work perfectly fine, however it is not a good design principle as it may collide with other functionality, using names like RED, BLUE or GREEN. This is also semantically strange, since I could say RED

Summarizing, in the answer I would like to see a solution adhering to good c++ design principles. I don't care for solutions that just work! This could be one of the three previously mentioned ways, using an enum, one class or inheritance.

EDIT2: Meanwhile I also though of a template based approach for the multiple-inheritance case. However, to be fairly honest, my knowledge of templates is not adequate yet to create something 'good'. The idea is based on functions like std::is_same and std::is_functional of the type_traits header.

#include <iostream>

class Color {};

class Red : Color {};
class Green : Color {};
class Blue : Color {};

template<class C1, class C2>
bool is_same_color();

template<class C1>
bool is_happy();

int main() {
    // your code goes here
    return 0;
}

It is not working, but I hope the idea get's across. Also, I realize is_same_color and is_happy should be classes with a operator() defined.

EDIT3: One could state that this is what I want:

enum Color {
  RED, GREEN, BLUE
  bool isHappy() { return this==GREEN || this==RED; }
  Color rotate() { return (this==RED ? GREEN (this==GREEN ? BLUE : RED)); }
  int intensity() { return (this==RED ? 11 (this==GREEN ? 12 : 4)); }
}

But that is of course, not valid c++.

like image 770
Herbert Avatar asked Aug 22 '26 18:08

Herbert


2 Answers

You may use a class and use specific instances (a la singleton) for the enum:

class Color
{
public:
    bool isHappy() const { return this == &Green || this == &Red; }
    const Color* rotate() const { return (this == &Red ? &Green : (this == &Green ? &Blue : &Red)); }
    int intensity() const {return mIntensity; }

    static const Color* red() { return &Red; }
    static const Color* green() { return &Green; }
    static const Color* blue() { return &Blue; }

private:
    // forbid to construct new instance: use only red(), green(), blue()
    explicit Color(int intensity) : mIntensity(intensity) {}
    Color(const Color&) = delete; 
private:
    int mIntensity;

private:
    static const Color Red;
    static const Color Green;
    static const Color Blue;
};

const Color Color::Red(11);
const Color Color::Green(12);
const Color Color::Blue(4);
like image 85
Jarod42 Avatar answered Aug 25 '26 08:08

Jarod42


Some other nice answers have been given, but I am afraid they don't use the C++ expression and clarity and conciseness to the full extent.

I propose the following solution:

class Color
{
public:
    virtual bool is_happy() = 0;
    virtual Color* rotate() = 0;
    virtual int intensity() = 0;

    static Color* const Red;
    static Color* const Green;
    static Color* const Blue;

    Color(Color const&) = delete;

private:
    Color(){}

    template<bool happiness, Color* const* rotation_result, int intensity_value>
    class Color_Generator;

    template<bool happiness, Color* const* rotation_result, int intensity_value>
    friend class Color_Generator;
};

template<bool happiness, Color* const* rotation_result, int intensity_value>
class Color::Color_Generator : public Color
{
public:
    bool is_happy()
    {
        return happiness;
    }

    Color* rotate()
    {
        return *rotation_result;
    }

    int intensity()
    {
        return intensity_value;
    }

    static Color_Generator<happiness, rotation_result, intensity_value> Instance;
};

template<bool happiness, Color* const* rotation_result, int intensity_value>
Color::Color_Generator<happiness, rotation_result, intensity_value>
Color::Color_Generator<happiness, rotation_result, intensity_value>::Instance;

Color* const Color::Red = &Color_Generator<true, &Green, 11>::Instance;
Color* const Color::Green = &Color_Generator<true, &Blue, 12>::Instance;
Color* const Color::Blue = &Color_Generator<false, &Red, 4>::Instance;

//==============
// Some usage follows

#include <iostream>

int main()
{
    Color* a = Color::Red;
    Color* b = Color::Green;
    Color* c = Color::Blue;

    std::cout << a->intensity() << std::endl;
    std::cout << b->is_happy() << std::endl;
    std::cout << (b->rotate() == c) << std::endl;
}

There are some more C++ features available to even further improve this code. For example, you might use virtual inheritance in order to split the definition of is_happy, rotate and intensity into their own 'facet' classes in the true spirit of C++.

like image 25
ach Avatar answered Aug 25 '26 07:08

ach



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!