由于多重继承而导致重复的变量

Did*_*dii 3 c++ multiple-inheritance

我有3个类A,BC声明为

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

现在类C将有2个变量varAvarB.在我的例子中,两个变量具有相同的含义(例如,物理对象的位置),因此总是需要相同,因为成员函数只会对自己的变量进行计算.


我想增加一个父类AB,但后来同样的问题仍然存在:

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
    }
};
Run Code Online (Sandbox Code Playgroud)

有谁知道这个问题的优雅解决方案?


编辑:上下文

ABPhysicsCollidable分别.该类Physics使对象具有加速度,速度和位置等变量.并包含几个成员函数,根据经过的时间计算下一个位置.另一个类Collidable使对象能够与其他对象进行交互(碰撞),在发生碰撞时定义它们的行为,同时还检查它们是否实际上是碰撞.此类包含位置和边界框等变量.

因此,重叠变量是位置,因为两个类都需要彼此独立.该类Collidable不需要继承,Physics因为例如墙不需要加速度和/或速度等变量,因为它是静态的.

我想使用继承,C因为它将是一个物理对象的对象,并且是一个可碰撞的对象.一个has-a关系似乎不合适,因此我选择了继承而不是组合.

Mar*_*k B 8

要解决您编写的问题,您可以使用虚拟父级,以便将其作为子类中的一个实例共享:

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.
    }
};
Run Code Online (Sandbox Code Playgroud)

但这种气味的设计可能会使用另一种外观.为什么两个不相关的类都具有相同的数据(在您的原始设计中)?稍微考虑一下这些事情,或许会有一个替代设计(基类中的抽象接口,使用模板算法将类绑定在一起的机制等).或者,如果您提供有关类关系的更多信息,我们可以提供C++ - 惯用解决方案.

编辑:

我相信我更喜欢的另一个想法是将位置的状态与物理和可碰撞对象分开,增加一个间接级别.所以物理和可碰撞两者都有指向外部位置状态对象的指针.因为它是外部的,所以它们都会引用并能够改变相同的共享状态.所需的所有权将决定使用的指针类型.

粗略的草图可能如下所示:

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);
}
Run Code Online (Sandbox Code Playgroud)

最后要注意的是is-a,虽然有用的指导方针,但不应该真正确定何时继承.它真正意味着你想要把C它作为一个物理或透明地用作一个物理或作为一个可碰撞的物质,而没有相关的代码真的知道它是一个C.如果这代表了您的需要,那么这就是您设计的真正考验(参见Liskov替代原则).