Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for a better way than virtual inheritance in C++

OK, I have a somewhat complicated system in C++. In a nutshell, I need to add a method to a third party abstract base class. The third party also provides a ton of derived classes that also need the new functionality.

I'm using a library that provides a standard Shape interface, as well as some common shapes.

class Shape
{
    public:
        Shape(position);
        virtual ~Shape();

        virtual position GetPosition() const;
        virtual void SetPosition(position);

        virtual double GetPerimeter() const = 0;

    private: ...
};

class Square : public Shape
{
    public:
        Square(position, side_length);
    ...
};

class Circle, Rectangle, Hexagon, etc

Now, here's my problem. I want the Shape class to also include a GetArea() function. So it seems like I should just do a:

class ImprovedShape : public virtual Shape
{
    virtual double GetArea() const = 0;
};

class ImprovedSquare : public Square, public ImprovedShape
{
    ...
}

And then I go and make an ImprovedSquare that inherits from ImprovedShape and Square. Well, as you can see, I have now created the dreaded diamond inheritance problem. This would easily be fixed if the third party library used virtual inheritance for their Square, Circle, etc. However, getting them to do that isn't a reasonable option.

So, what do you do when you need to add a little functionality to an interface defined in a library? Is there a good answer?

Thanks!

like image 289
Imbue Avatar asked Nov 28 '22 05:11

Imbue


2 Answers

Why does this class need to derive from shape?

class ImprovedShape : public virtual Shape
{
    virtual double GetArea() const = 0;
};

Why not just have

class ThingWithArea 
{
    virtual double GetArea() const = 0;
};

ImprovedSquare is a Shape and is a ThingWithArea

like image 124
Dave Hillier Avatar answered Dec 19 '22 06:12

Dave Hillier


We had a very similar problem in a project and we solved it by just NOT deriving ImprovedShape from Shape. If you need Shape functionality in ImprovedShape you can dynamic_cast, knowing that your cast will always work. And the rest is just like in your example.

like image 39
Gorpik Avatar answered Dec 19 '22 08:12

Gorpik