0

Suppose we have 3 classes Button, Clickable and Rectangle.
Neither of them are abstract and can exist on their own. All of them have a position member variable. When the Button class inherits from Clickable and Rectangle they should share a common position variable.
My implementation:

struct Positionable {
    struct Position {
        int x, y;
    } position;
};
struct Rectangle: virtual public Positionable {
    // ...
};
struct Clickable : virtual public Positionable {
    // ...
};
struct Button : virtual public Positionable, public Rectangle, public Clickable {
    Button() {
        this->position.x = 1;
        assert(Rectangle::position.x == 1);
        assert(Clickable::position.x == 1);
        assert(Positionable::position.x == 1);
    }
} test;

The problem with this (besides the 3 forms of the word position) is that I feel, that I'm breaking the composition over inheritance principle, because I inherit only to include a variable.
Is there a design pattern with the same behavior? How can I use composition in this situation?

EDIT:

I'm looking for a solution where the Button inherits from Clickable and from Rectangle, because it's an is-a relationship. (It might not be the best example, but assume that it's true)
I also don't want to inherit from Positionable, because it's a has-a relationship.
And I want the same behavior like my implementation, so:

  • All of them have a Position position
  • When they inherit from each other, they share this variable
  • I don't use setters/getters

Basically I want something like virtual variables, but c++ doesn't have that feature yet, so I'm looking for a sensible replacement.

csiz
  • 78
  • 7

2 Answers2

1

I don't see your problem exactly, however you can use references to achieve this. You can do something like:

struct Position{
    int x,y;
};

class Rectangle {
    public:
        Rectangle(Position& p) : pos(p) {}
        ~Rectangle() {}
        Position getPos(){ return pos; }
    protected:
        Position& pos;
};

class Clickable {
    public:
        Clickable(Position& p) : pos(p) {}
        ~Clickable() {}
        Position getPos(){ return pos; }
    protected:
        Position& pos;
};

class Button {
    public:
        Button(int x, int y) : pos({x,y}), a(this->pos), b(this->pos) {}
        ~Button() {}
        Position getPos(){ return pos; }
    protected:
        Position pos;
        Clickable a;
        Rectangle b;
};

This is very messy though. Also it makes it a pain to use the raw Rectangle, and Clickable classes if you ask me. Pointers can achieve this as well, if that is what you prefer.

Lala5th
  • 1,137
  • 7
  • 18
  • 1
    If opinion based questions would be allowed on stackoverflow my main question would have been that is it an anti-pattern or not. The problem is that if I want to include more variables I need to make a bunch of useless structs and have to inherit from them, which can be hard to understand for the programmer who would see my code, because every inheritance can hide any number of variables and functions. Probably I want something like virtual variables, but I hoped that there is a nice workaround. – csiz Jul 06 '21 at 01:41
1

Inheritance models an is-a relationship. If Horse inherits from Animal, then a Horse is an Animal, because all properties an animal has are also properties of a horse.

Now, in your example, does it make sense to say that a Button is Clickable? Yes, so inheritance is an applicable tool for the job. Does it make sense to say that a Button is a Rectangle? Well, now we get into muddy waters.

If we intend to use a Button through its Rectangle sub-interface (perhaps a simple renderer could take in rectangle-deriving objects and render them), then inheritance is also appropriate here. But if inheritance is used because it's proper OOP and it's what needs to be done, then no.

Weigh what you need, see if it makes logical sense. Think if you should, before you think if you could.

PS: I don't understand why Clickable isn't abstract. It sounds like an interface. If it isn't an interface, perhaps there's a better name for the concept you are trying to model.

EDIT

It occurred to me that, if you are using C++, you might want to look into private inheritance. This is the kind of implementation-inheritance you are talking about. C++ FAQ about it: https://isocpp.org/wiki/faq/private-inheritance

super
  • 278
  • 1
  • 11
  • My problem isn't about the relationship between `Button` , `Rectangle` and `Clickable`, I want these to be given. I wasn't really clear about this, so I updated my question. The problem that I don't want to inherit from `Positionable `, because it's not an is-a relationship and it doesn't have any functionality, but I still want the shared `position` variable. – csiz Jul 23 '21 at 05:22
  • 1
    Thank you for updating the question, I'm sorry I misunderstood. Privately and virtually inheriting from `Positionable` seems to me like an alright approach. It has the semantics you want, without exposing this inheritance to the outside. If you want to *completely* avoid inheritance, then you might try keeping a `std::shared_ptr` as a member that's distinct for every class and setting that to point to the same position instance, so it's effectively shared. I think this solution is worse though, because of the dynamic allocation. – super Jul 23 '21 at 20:26