【问题标题】:Why doesn't my inherited interface use my base class's override?为什么我继承的接口不使用我的基类的覆盖?
【发布时间】:2013-06-16 14:39:43
【问题描述】:

我遇到了接口和多重继承的问题。我希望设计我的程序,以便一个更新调用处理各种对象,每个行为“构建块”都隐藏在一个函数中。

例如,我想将一个生物从 A 点移动到 B 点,无论它是否必须执行移动前/移动后操作。但是,我的多重继承方案失败了(下面,有错误 rem'd),让我觉得我需要在某个地方复制代码。

显然我对此理解得不够好! (但我正在努力学习)

第一季度。为什么 IPhysics::Move 不能在 CreatureAirborne 类中“看到”Creature::Move()?

第二季度。我是否完全错过了接口和/或多重继承的正确使用?如果是这样,任何指导表示赞赏!

#include <deque>
#include <memory>

class IGameObject
{
public:
    virtual ~IGameObject() {}

    virtual void Update() = 0;
};

class IPhysics
{
public:
    virtual ~IPhysics() {}

    virtual void Move() = 0;
};

class IPhysicsFlight : public IPhysics
{
public:
    virtual ~IPhysicsFlight() {}

    virtual void Land() = 0;
    virtual void TakeOff() = 0;
};

class Creature : public IGameObject, IPhysics
{
protected:
    virtual void Move() {}

public:
    Creature() {}
    virtual ~Creature() {}

    virtual void Update() {}
};


class CreatureAirborne : public Creature, IPhysicsFlight
{
private:
    virtual void Land() {}
    virtual void TakeOff() {}

public:
    CreatureAirborne() {}
    virtual ~CreatureAirborne() {}

    virtual void Update();
};

void CreatureAirborne::Update()
{
    TakeOff();

    Creature::Move();

    Land();
}

int main()
{
    std::deque<std::shared_ptr<Creature>> creatures;

    std::shared_ptr<Creature> cow(new Creature);

    creatures.push_back(cow);

// The butterfly fails to compile with 'cannot instantiate; void IPhysics::Move(void) is abstract'

//  std::shared_ptr<CreatureAirborne> butterfly(new CreatureAirborne);

//  creatures.push_back(butterfly);

    for (auto i : creatures)
    {
        i->Update();
    }
}

【问题讨论】:

  • 为什么 Move 在 Creature 中是 protected 而在 IPhysics 中是 public?我担心这会引起一些问题,因为我认为您无法限制可见性,因此编译器可能会认为您定义了另一个函数。不确定,不是 C++ 大师。 :)
  • @MarkRansom:你说得对,我被 C#/Java/所有其他语言愚弄了... :)
  • 嗯...为什么要这样?显然,空中的生物不能像非空中的生物那样移动……;)
  • 您知道class Creature : public IGameObject, IPhysicsIPhysics 的继承是私有的吗?

标签: c++ interface multiple-inheritance


【解决方案1】:

它在某种程度上必须遵循您的层次结构,但它在编译器方面看起来是正确的评估。

您在任何地方都没有虚拟继承,因此CreatureAirborne 将在某些时候具有重复的基类。您将拥有两个 IPhysics 实例。 Move,即从那里抽象出来的,在 Creature 分支上实现,但在 IPhysicsFlight 上仍然是抽象的。

您可以通过在某处使用虚拟继承或通过在后代中实现 Move(比如只调用存在的父版本)来解决这种情况。

【讨论】:

  • +1,请注意,从纯接口继承可能应该是虚拟的(即使是从具有逻辑的空基数,如果您不需要多个基数也是有意义的),因为它不会产生额外的成本和修复这类问题。
  • @Balog Pal - 该分支术语有帮助。我忘记了 IPhysicsFlight 不会“通过”Creature,而是在层次结构中位于它旁边。所以我将不得不写 CreatureAirborn::Move(),毕竟我接受它?但它可以调用 Creature::Move(),这就足够了。谢谢!
  • @DavidRodríguez-dribeas - 很好的提示,谢谢!
【解决方案2】:

我会以不同的方式看待事物

class CreatureAirborne : public IPhysicsFlight,Creature

代码运行时

new CreatureAirborne ()

编译器将尝试构建 IPhysicsFlight 基类和 Creature 基类,而 IPhysics 是两者的基类这一事实并没有起到任何作用,反而会造成混淆。就编译器而言,IPhysicsFlight 是抽象的,而 CreatureAirborne 则没有实施移动

钻石问题实际上会在您进行时发挥作用

(new CreatureAirborne ())->Move()

【讨论】:

    猜你喜欢
    • 2016-06-14
    • 2014-09-09
    • 1970-01-01
    • 2015-09-02
    • 2016-12-02
    • 2012-11-01
    • 2014-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多