Search code examples
c++oopinheritancedynamic-castcar-analogy

How can I avoid dynamic_cast in my C++ code?


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?


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.