Question

Let's say I have the following class structure:

class Car;
class FooCar : public Car;
class BarCar : public Car;

class Engine;
class FooEngine : public Engine;
class BarEngine : public Engine;

Let's also give a Car a handle to its Engine. A FooCar will be created with a FooEngine* and a BarCar will be created with a BarEngine*. Is there a way to arrange things so a FooCar object can call member functions of FooEngine without downcasting?

Here's why the class structure is laid out the way it is right now:

  1. All Cars have an Engine. Further, a FooCar will only ever use a FooEngine.
  2. There are data and algorithms shared by all Engines that I'd rather not copy and paste.
  3. I might want to write a function that requires an Engine to know about its Car.

As soon as I typed dynamic_cast when writing this code, I knew I was probably doing something wrong. Is there a better way to do this?

UPDATE:

Based on the answers given so far, I'm leaning towards two possibilities:

  1. Have Car provide a pure virtual getEngine() function. That would allow FooCar and BarCar to have implementations that return the correct kind of Engine.
  2. Absorb all of the Engine functionality into the Car inheritance tree. Engine was broken out for maintenance reasons (to keep the Engine stuff in a separate place). It's a trade-off between having more small classes (small in lines of code) versus having fewer large classes.

Is there a strong community preference for one of these solutions? Is there a third option I haven't considered?

Was it helpful?

Solution

I'm assuming that Car holds an Engine pointer, and that's why you find yourself downcasting.

Take the pointer out of your base class and replace it with a pure virtual get_engine() function. Then your FooCar and BarCar can hold pointers to the correct engine type.

(Edit)

Why this works:

Since the virtual function Car::get_engine() would return a reference or a pointer, C++ will allow derived classes to implement this function with a different return type, as long as the return type only differs by being a more derived type.

This is called covariant return types, and will allow each Car type to return the correct Engine.

OTHER TIPS

Just one thing I wanted to add: this design already smells bad to me because of what I call parallel trees.

Basically if you end up with parallel class hierarchies (as you have with Car and Engine) then you're just asking for trouble.

I would rethink if Engine (and even Car) needs to have subclasses or those are all just different instances of the same respective base classes.

You could also templatize the Engine type as follows

template<class EngineType>
class Car
{
    protected:
        EngineType* getEngine() {return pEngine;}
    private:
        EngineType* pEngine;
};

class FooCar : public Car<FooEngine>

class BarCar : public Car<BarEngine>

I don't see why a car can't be composed of an engine (if BarCar will always contain BarEngine). Engine has a pretty strong relationship with the car. I would prefer:

class BarCar:public Car
{
   //.....
   private:
     BarEngine engine;
}

Would it be possible for the FooCar to use the BarEngine?

If not, you might want to use an AbstractFactory to create the right car object, with the right engine.

You can store the FooEngine in FooCar, BarEngine in BarCar

class Car {
public:
  ...
  virtual Engine* getEngine() = 0;
  // maybe add const-variant
};

class FooCar : public Car
{
  FooEngine* engine;
public:
  FooCar(FooEngine* e) : engine(e) {}
  FooEngine* getEngine() { return engine; }
};

// BarCar similarly

The problem with this approach is that getting an engine is a virtual call (if you're concerned about that), and a method for setting an engine in Car would require downcasting.

I think that it depends if Engine is only privately used by Car and its children or if you also want to use it in other objects.

If Engine functionalities are not specific to Cars, I would use a virtual Engine* getEngine() method instead of keeping a pointer in the base class.

If its logic is specific to Cars, I would prefer putting the common Engine data/logic in a separate object (not necessarily polymorphic) and keep FooEngine and BarEngine implementation in their respective Car child class.

When implementation recycling is more needed than interface inheritance, object composition often offer greater flexibility.

Microsoft's COM is kind of clunky, but it does have a novel concept - if you have a pointer to an interface of an object, you can query it to see if it supports any other interfaces using the QueryInterface function. The idea is to break your Engine class into multiple interfaces so that each can be used independently.

Allowing I haven't missed something, this should be rather trivial.

The best way to do this is to create pure virtual functions in Engine, that are then required in derived classes that are to be instantiated.

An extra credit solution would probably be to have an interface called IEngine, that you instead passs to your Car, and every function in IEngine is pure virtual. You could have a 'BaseEngine' that implements some of the functionality you want (i.e., 'shared') and then have leaf ones off of that.

The interface is nice should you ever have something you want to 'look' like an engine, but probably isn't (i.e., mock test classes and such).

Is there a way to arrange things so a FooCar object can call member functions of FooEngine without downcasting?

Like this:

class Car
{
  Engine* m_engine;
protected:
  Car(Engine* engine)
  : m_engine(engine)
  {}
};

class FooCar : public Car
{
  FooEngine* m_fooEngine;
public:
  FooCar(FooEngine* fooEngine)
  : base(fooEngine)
  , m_fooEngine(fooEngine)
  {}
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top