The key in designing a system is to always program to an interface and not an implementation. The interface describes the behavior of the object but doesn't care how the behavior happens. The impl follows the interface and implements the actual behavior while adhering to the interface.
So if we were building a vehicle class I would do this:
Code:
class IVehicle
{
public:
virtual ~IVehicle() { }
virtual void Accelerate() = 0;
virtual void Decelerate() = 0;
virtual void TurnLeft() = 0;
virtual void TurnRight() = 0;
};
This interface defines the behavior of a vehicle. As long as you adhere to the interface you can implement these functions in any way you want. I have not defined how a vehicle accelerates, turns, etc., but I have defined that it does have this behavior.
In addition to this you could add ITransmission and IEngine which would define the behavior of the engine and the transmission.
This would allow us to derive from IVehicle, IEngine, and ITransmission to create our final vehicle. It would allow us to define several types of vehicles, engines, and transmissions that could all basically be dropped in without changing any of the interface code. This means our system is extremely flexible, powerful, and easily extended. I would envision that IEngine and ITransmission would be aggregated into the vehicle impl since a vehicle is not a transmisson or engine but certainly does have both.
So for example:
Code:
class IEngine
{
public:
virtual ~IEngine { }
virtual void StartEngine() = 0;
virtual void StopEngine() = 0;
virtual unsigned int GetNumberOfCylinders() = 0;
virtual unsigned int GetHorsePower() = 0;
...
};
class ITransmission
{
public:
virtual ~ITransmission() { }
virtual void ShiftUp() = 0;
virtual void ShiftDown() = 0;
virtual unsigned int GetNumberOfGears() = 0;
virtual float GetGearRatio(unsigned int gear) = 0;
};
class Car : public IVehicle
{
public:
Car();
virtual ~Car()
virtual void Accelerate();
virtual void Decelerate();
virtual void TurnLeft();
virtual void TurnRight();
void AttachTransmission(ITransmission *pTransmission);
void AttachEngine(IEngine *m_pEngine);
...
...
private:
IEngine *m_pEngine;
ITransmission *m_pTransmission;
};
Now a car is a vehicle with an engine and a transmission. As long as the engine implementes the IEngine interface and the transmission implements the ITransmission interface then they can be attached to this car. I would envision that Car would be used as a base class for all cars. Technically you could derive trucks and motorcyles from Car as well but for clarity's sake I would not.
I left out a possible IDifferential would allow you to attach different differentials (or differential gears) to the car allowing you to change the final drive gear. As well you would need ITire which would describe a tire and allow you to create many different types of tires and attach them to your car. Note that you would not want to aggregate a specific amount of ITire pointers in car because this would limit you to that amount. You probably would want some type of ITireSystem object that would encapsulate how many tires belonged on the car. Given this you very well could design and test a car that had less/more than 4 tires which might be useful for other types of vehicles.
If your physics code took all of this information into account you would essentially have a very robust simulation of a vehicle in which you could swap out tires, engines, trannies, diffs, etc. and test all of them on your virtual track. You would be able to design tractors, trucks, cars, race cars, semis, etc. all with this simple interface. Thus the power of polymorphism.