Stewii
Stewii

Reputation: 82

Why doesn't my inherited interface use my base class's override?

I have a problem with interfaces and multiple inheritance. I hope to design my program such that one update call processes a variety of objects, with each behavioral 'building block' tucked away in a single function.

For example, I'd like to move a creature from point A to B in one place, regardless of whether it must perform pre/post move actions. But, my multiple inheritance scheme fails (below, with the bug rem'd), making me think I'd need to duplicate code somewhere.

Clearly I don't understand this well enough! (but I'm working hard to learn it)

Q1. Why can't IPhysics::Move 'see' Creature::Move(), in the CreatureAirborne class?

Q2. Am I completely missing the proper usage of interfaces and/or multiple inheritance? If so, any guidance is appreciated!

#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();
    }
}

Upvotes: 3

Views: 109

Answers (2)

sethi
sethi

Reputation: 1889

I would look at things little differently

class CreatureAirborne : public IPhysicsFlight,Creature

While the code runs

new CreatureAirborne ()

The compiler will try to build IPhysicsFlight base class and Creature base class and the fact that IPhysics is a base class to both doesn't play any role rather than confusing.As far as compiler is concerned IPhysicsFlight is abstract and CreatureAirborne did not implement Move

The diamond issue will actually come into play when you do a

(new CreatureAirborne ())->Move()

Upvotes: 0

Balog Pal
Balog Pal

Reputation: 17183

It's somewhat had to follow your hierarchy, but it looks correct evaluation on the compiler's part.

You don't have virtual inheritance anywhere, so CreatureAirborne will have duplicated base classes from some point. You will have two instances of IPhysics. Move, that is abstract from there is implemented on the Creature branch but remains abstract on IPhysicsFlight.

You can cure the situation by using virtual inheritance somewhere, or by implementing Move in descendant (say just calling the parent version where it exists).

Upvotes: 3

Related Questions