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

时间:2013-12-16 17:53:17

标签: c++ multiple-inheritance

我有3个课程ABC,声明为

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

现在,课程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
    }
};

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


编辑:上下文

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

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

我想为C使用继承,因为这将是是一个物理对象和是一个可碰撞对象的对象。 有一个关系似乎不合适,因此我选择了继承而不是合成。

1 个答案:

答案 0 :(得分: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.
    }
};

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

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