Question

I have 3 classes A, B and C, declared as

class A {
    int varA;
};
class B {
    int varB;
};
class C : public A, public B {
    void setVar(int var) {
        varA = var;
        varB = var; // <- duplicate
    }
};

Now class C will have 2 variables varA and varB. In my case, both variables have the same meaning (eg. position of a physical object) and thus always need to be the same, since member functions will only do calculations on their own variable.


I thought about adding a parent class for A and B, but then the same problem persists:

class Parent {
public:
    int var;
};

class A : public Parent {};
class B : public Parent {};

class C : public A, public B {
    void setVar(int v) {
        A::var = v;
        B::var = v; // <- duplicate
        // or
        var = v; // <- compiler error: Ambiguous call
    }
};

Does anyone know an elegant solution to this problem?


Edit: Context

Classes A and B are Physics and Collidable respectively. The class Physics enables an object to have variables like acceleration, speed and position. And consists a couple of member functions to calculate the next position based on the time elapsed. The other class Collidable enables an object to interact (collide) with other objects, defining their behavior when a collision occurs while also checking whether they are in fact colliding or not. This class has variables such as position and a bounding box.

The overlapping variable is thus the position since both classes need it independently from each other. The class Collidable does not need to inherit from Physics because a wall for example does not need variables like acceleration and/or speed since it's static.

I wanted to use inheritance for C because that will be an object that is-a physics object and is-a collidable object. A has-a relation does not seem appropriate, hence I chose inheritance over composition.

Was it helpful?

Solution

To solve your problem as written, you could use a virtual parent so that it's shared as one instance in the child class:

class Parent {
public:
    int var;
};

class A : public virtual Parent {};   // ** Note I added virtual here
class B : public virtual Parent {};   // ** Note I added virtual here

class C : public A, public B {
    void setVar(int v) {
        var = v; // No longer ambiguous.
    }
};

But this smells of a design that could use another look. Why do two unrelated classes both have the same data within them (in your original design)? Think about these things a bit and perhaps an alternate design will come to you (abstract interface in a base class, mechanism to tie the classes together using template algorithms, etc). Alternately if you provide more information about the relationship of your classes we can provide a C++-idiomatic solution.

EDIT:

Another idea that I believe I like better would be to seperate the position's state from the physics and collidable objects, adding one more level of indirection. So physics and collidable both would have pointers to an external position state object. Since it's external, both would refer to and be able to mutate the same shared state. The desired ownership would dictate the type of pointer used.

A rough sketch might look like this:

class Position {};

class A
{
public:
    explicit A(const shared_ptr<Position>& pos) : pos_(pos) {}

private:
    shared_ptr<Position> pos_;
};

class B
{
public:
    explicit B(const shared_ptr<Position>& pos) : pos_(pos) {}

private:
    shared_ptr<Position> pos_;
};

class C : public A, public B
{
public:
    explicit C(const shared_ptr<Position>& pos) : A(pos), B(pos) {}
};

int main()
{
    shared_ptr<Position> pos = make_shared<Position>();

    C object_of_type_C(pos);
}

Finally note that is-a, while a useful guideline, shouldn't really determine when you inherit. What it really means is that you want to take a C and transparently use it as a physics OR as a collidable without the code in question really knowing it's a C. If this represents your need then that's the real test for your design (see Liskov Substitution Principle).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top