I am building a series of classes to describe objects similar to cars. Each car class contains state variables that are relevant to the data available at any given time. For example, perhaps there is fuel data available, I create a FuelCar class. If I also have material data and price data I create MaterialCar and PriceCar. The purpose of this is that for any given project I may have only a subset of those kinds of data available to me. Therefore, I want to be able to create inherited car classes based on the kind of data available to me.
If, for example, I have fuel data and material data I want to be able to create a class FuelMaterialCar which not only has the functionality of the FuelCar and MaterialCar classes but which incorporates additional methods that are only available with the combination of said data.
All of this is fairly straightforward inheritance and I have not had trouble implementing this kind of thing in similar projects in the past. The difficulty is the further requirement.
Each kind of car class is a composite class of several layers. Each Car has an engine, each engine has a powerTrain, and each powerTrain has cylinders. These are each represented as classes of their own, and each of them has a different version depending on which kind of data is available, just as with the car class. Thus there is a FuelEngine, FuelPowerTrain, FuelCylinder ... etc.
The car classes each need to have access to their engins, powertrains and cylinders, and because each of these objects is a different class I created a template class for each class PrimitiveCar, PrimitiveEngine, PrimitivePowerTrain, PrimitiveCylinder. Each of these primitive classes contain vectors and maps to the various contained components. Below are examples of my code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
template <class CylinderT, class PowerTrainT, class EngineT>
class PrimitiveCar{
protected:
CylinderT* currentCylinder_p;
PowerTrainT* currentPowerTrain_p;
EngineT* currentEngine_p;
std::vector<CylinderT*> cylinders;
std::vector<CylinderT*>::iterator cylinders_it;
map<std::string, PowerTrainT*> powerTrains;
map<std::string, PowerTrainT*>::it powerTrains_it;
std::vector<EngineT*> engines;
std::vector<EngineT*>::iterator engines_it;
/*...*/
};
template <class CylinderT, class PowerTrainT>
class PrimitiveEngine{
protected:
CylinderT* currentCylinder_p;
PowerTrainT* currentPowerTrain_p;
std::vector<CylinderT*> cylinders;
std::vector<CylinderT*>::iterator cylinders_it;
map<std::string, PowerTrainT*> powerTrains;
map<std::string, PowerTrainT*>::it powerTrains_it;
/*...*/
};
template <class CylinderT>
class PrimitivePowerTrain{
protected:
CylinderT* currentCylinder_p;
std::vector<CylinderT*> cylinders;
std::vector<CylinderT*>::iterator cylinders_it;
/*...*/
};
class PrimitivePowerTrain{
protected:
/*...*/
};
| |
Each of my classes will inherit from its respective primitive class so as to give it access to the appropriate container variables. For example, with the fuel class category.
1 2 3 4 5 6 7 8
|
class FuelCar: public virtual PrimitiveCar<FuelCylinder,FuelPowerTrain,FuelEngine>{/*...*/};
class FuelEngine: public virtual PrimitiveEngine<FuelCylinder,FuelPowerTrain>{/*...*/};
class FuelPowerTrain: public virtual PrimitivePowerTrain<FuelCylinder>{/*...*/};
class FuelCylinder: public virtual PrimativeCylinder{/*...*/};
| |
I am able to get this to work without any difficulty for each kind of car alone, but when I try to combine them I get many ambiguity problems. For example, lets say I have all three kinds of data available to me and I want to use a car which inherits from each type of car previously written, call is CompleteCar. The complete category of classes are written to inherit as follows.
1 2 3 4 5 6 7 8
|
class CompleteCar: public virtual PrimitiveCar<CompleteCylinder,CompletePowerTrain,CompleteEngine>, public virtual FuelCar, public virtual MaterialCar, public virtual PriceCar{/*...*/};
class CompleteEngine: public virtual PrimitiveEngine<CompleteCylinder,CompletePowerTrain>, public virtual FuelEngine, public virtual MaterialEngine, public virtual PriceEngine{/*...*/};
class CompletePowerTrain: public virtual PrimitivePowerTrain<CompleteCylinder> public virtual FuelPowerTrain, public virtual MaterialPowerTrain, public virtual PricePowerTrain{/*...*/};
class CompleteCylinder: public virtual PrimitiveCylinder, public virtual FuelCylinder, public virtual MaterialCylinder, public virtual PriceCylinder{/*...*/};
| |
Thus, my inheritance hierarchy is as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
templateClass
PrimativeCar<________________________________
^ ^ ^ |
| | |________________ |
| | | |
| |____FuelCar MaterialCar Price Car
| ^ ^ ^
| ________| | |
| | _____________________| |
| | | ______________________________________|
| | | |
| | | |
| | | |
CompleteCar
| |
The above inheritance structure is identical for the each of the various CompletePowerTrain, ComplateEngine, and CompleteCylinders classes. And each inheritance is virtual.
I am getting a lot of ambiguous reference errors from my compiler now. I am surprised by this because I thought the purpose of the virtual marker was to avoid such ambiguity.
Any help shedding light on this issue would be create appreciated. Sorry for the long chunks of code.