• 13
• 18
• 19
• 27
• 10

[C++] Avoid duplicate code in class hierarchy

This topic is 3719 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

class Vehicle { ... };

class Bike : public Vehicle { ... };
class MotorBike : public Bike { ... };

class GliderPlane : public Vehicle { ... };
class Plane : public GliderPlane { ... };

At this point I want to add engines to some of the vehicles like MotorBike and Plane. The options I see here is to add a engine object to each class that should have one, but that would probably result in a lot of duplicate code. What I realy want to do is to add another layer, something like this
class Vehicle { ... };

class VehicleWithEngine : public Vehicle  { ... };
class VehicleWithoutEngine : public Vehicle  { ... };

...

But that is even worse, now I can't let MotorBike inherit from Bike anymore which seemed to make sense in the first case. Is there a common way to make the pices fall into place here? Can refactoring, multiple inheritance or something like that provide a solution, or is a class hierarchy just not suited for this?

Share on other sites
Multiple inheritance with virtual base classes would work, although just refactoring the design to a composition-based approach might work as well.

Share on other sites
When you have multiple concepts that need to be mixed and matched, you need multiple hierarchies rather than just one. Look into patterns like the Bridge Pattern.

Share on other sites
Inheritance is often mis-applied to concepts it doesn't apply to.

Is-a relationship is where inheritance is used.
Has-a relationship is where composition is used.

Quote:
 The options I see here is to add a engine object to each class that should have one, but that

Vehicle has-a engine.
struct Vehicle {  Engine *e;};

What about bikes and motor bikes?

A bicycle is-a vehicle that has-a two wheels. Bicycles engine is human. Human is-a engine
struct Human : public Engine {  //};struct Bicycle : public Vehicle {  Bicycle( Engine *e ) : Vehicle( e ), n_wheels(2) {}  int n_wheels;};

Hmm, is a motorbike really different from bicycle? Or is it really just a bicycle with internal combustion engine instead of human.
struct InternalCombustionEngine : public Engine {  int n_strokes;};struct TwoStrokeEngine : public InternalCombustionEngine {  TwoStrokeEngine : InternalCombustionEngine( 2 )};struct MotorBike : public Bicycle {  MotorBike( ) : Bicycle( new TwoStrokeEngine() )};

But - is a plane really just a glider plane with engines? What powers a glider plane? Interaction of speed, lift, gravity and drag.
struct GravityEngine : public Engine {};struct JetEngine : public Engine {};struct Plane : public Vehicle {  LiftingSurfaces *ls; // wings would probably work too, but many aircraft don't have them}struct GliderPlane : public Plane {  GliderPlane : Plane( new GravityEngine() ) {}};struct PassengerPlane : public Plane {  PassengerPlane : Plane( new JetEngine() ) {}};

Obviously, limitations become obvious - a vehicle can have multiple sources of propulsion - a motor bike can use human propulsion, or it can even use GravityEngine - it generates much less lift than a glider plane, but people can control them a bit while in the air.

Just be clear about the is-a and has-a relationship, then model according to that.