-1

I am studying multiple inheritance, and I read that it is considered bad design.

I created an example where multiple inheritance would be useful, and I have not found a way to rewrite it to remove multiple inheritance.
Furthermore, many languages do not support multiple inheritance and a new design is needed.

The 'Animal' class implements many things that all animals do.
The 'AquaticAnimal' class implements everything about water.
The 'TerrestrialAnimal' class implements everything about animal on land.

The 'Amphibious' class was created for animals that can do everything that 'AquaticAnimal' and 'TerrestrialAnimal' can do.
The application needs to use 'Amphibious' animals in the classes: Zoo, Aquarius, Plains and AmphibiousRace.

Despite virtual inheritance, the diamond problem continues, because calling Amphibious.eat() will call Animal.eat() twice and it will lead to inconsistent state.

It is not a real programming language, but it is like Java/C++.

class Animal{
  private:
    Place birthplace;
    String name;
    List likesToEat;
    Stomach stomach;

  public:
    virtual void growl(){ ... }

    virtual int eat(Food food){
        ... test if likes
        ... many operations
        chew()
        ...
        stomach.fill(food);
    }
}

class FlyingAnimal extends Animal {
  private:
    Wings wings;
  public:
    void fly(){ ...  wings.move(); ... }
}
class AquaticAnimal extends Animal{
  private:
    Flipper flipper;

  public:
    void swim(){ ... flipper.move(); ...  }

    int eat(Food food){
       int x = Animal.eat(food);
       ... use x
       flipper.nourish(food);
    }
}
class TerrestrialAnimal extends Animal{
  private:
    Legs legs;

  public:
    void run(){ ... legs.move(); ...  }

    int eat(Food food){
       int x = Animal.eat(food);
       ... use x
       legs.nourish(food);
    }
}
class Amphibious extends AquaticAnimal, TerrestrialAnimal{
  public:
    int eat(Food food){
        AquaticAnimal.eat(food);
        TerrestrialAnimal.eat(food);
        //PROBLEM: Animal.eat() will be called twice.
    }
}

//------------------------------------------
class Zoo {
  public:
    void add/remove(Animal a);
    void feed(Animal a);
    void show(Animal a);
}
class Aquarius {
  public:
    void add/remove(AquaticAnimal a);
}
class Plains {
  public:
    void add/remove(TerrestrialAnimal a);
}
class HighPeaks {
  public:
    void add/remove(FlyingAnimal a);
}
class AmphibiousRace {
  public:
    void add/remove(Amphibious a);
    void enterIntoLake(Amphibious a);
    void exitFromLake(Amphibious a);
}
Squall
  • 4,344
  • 7
  • 37
  • 46
  • There's not even a question mark in this. Do you have a question, or is this just a brain dump? – Chris Eberle May 03 '12 at 01:42
  • The question is: how to rewrite this code to remove multiple inheritance? – Squall May 03 '12 at 01:53
  • I know this is an old question, but today the best way to solve this is to use mixins or traits. See: http://alisoftware.github.io/swift/protocol/2015/11/08/mixins-over-inheritance/ – digory doo Jun 24 '18 at 15:04

1 Answers1

0

If it's the legs and flippers that differentiates aquatic and terrestrial animals, is it really valid to say amphibious animals inherit from both? Not many animals have both legs and flippers.

Either way, you could use more of a composition approach where you pass the pieces that are needed into the class:

class Animal{
  private:
    Place birthplace;
    String name;
    List likesToEat;
    Stomach stomach;

  public:

    virtual IEnumerable<Movement > Movements { get; }
    virtual IEnumerable<IAppendage> Appendages{ get; }

    virtual void growl(){ ... }

    virtual int eat(Food food){
        ... test if likes
        ... many operations
        chew()
        ...
        stomach.fill(food);
    }
}

interface IAppendage {
   void Move();
}

class Wings : IAppendage {}
class Legs: IAppendage {}
class Flippers : IAppendage {}


class Movement {
  private:
  IAppendage AppendageForMovement { get; }
  public :
  void Go(){
    AppendageForMovement.Move();
  }
}

class FlyingMovement : Movement {}
class RunningMovement : Movement  {}
class SwimmingMovement : Movement {}

class AmphibiousAnimal extends Animal {

private: 
   Flippers flipper;
   Legs leg;
    virtual IEnumerable<Movement > Movements { get { return new Movement [] { new SwimmingMovement( flipper ), new RunningMovement( leg ) } ; }
    virtual IEnumerable<IAppendage> Appendages { get { return new IAppendage[] {new Wings() } }

  public:
    void fly(){ // find flying movement
           ...  
           flyingMovement.Go(); 
           ... 
    }
}

That's a bit of a rough example, but hopefully it gives you the idea. Instead of trying to tie all the functionality into base classes try passing the functionality you need in. If you need more than one type of functionality (e.g. running and walking and swimming) then you simply pass in more helper classes to provide that functionality.

Mike Parkhill
  • 5,511
  • 1
  • 28
  • 38