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:
Car
s have an Engine
. Further, a FooCar
will only ever use a FooEngine
.Engine
s that I'd rather not copy and paste.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:
Car
provide a pure virtual getEngine()
function. That would allow FooCar
and BarCar
to have implementations that return the correct kind of Engine
.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?
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With