I have struggled with this design problem for some time. I will do my best to explain what I am trying to do and the various approached that I have seen, what I am trying and wh
Maybe you could change data models to implement something component based. Each component could contain the same state information you mentioned for the different types. And you could inherit virtual functions
class Galaxy
{
// galaxy information
// Virtual functions shared among galaxies
virtual void sharedGalaxyFunction() = 0;
// Vector containing all solar systems in this galaxy
std::vector<SolarSystem*> solarSystems_;
};
class SolarSystem
{
// solar system info
// Virtual functions shared among all solar systems
virtual void sharedSolarSystemFunction() = 0;
// Vector containing planets
std::vector<Planets*> planets_;
};
// etc for planets...
You could then inherit the different types of solar systems or galaxies to create the special cases and fill out the virtual function calls
class CoolSolarSystem : public SolarSystem
{
// Special variables
// Fill in the virtual function
void sharedSolarSystemFunction();
};
You could then populate the containers inside the different base types with the pointers to your special types. You should be able to avoid a cast back to the special type if the virtual function calls handle enough of that information.
So if I understand your question right:
This sounds like a case for boost::any
So now your Galaxy is:
#include <list>
#include <boost/any.hpp>
typedef std::vector<boost::any> collection;
class Galaxy
{
collection SolarSystems;
public:
...methods...
};
class SolarSystem
{
collection PlanetarySystems;
public:
...methods...
};
class PlanetarySystem
{
collection Moons;
public:
...methods...
};
Ofcourse, this doesn't really do anything, but does allow you to group them. In order to do anything useful (call a method) you will still have to detect the type, cast it to that type and then run the code you need to.
However, what this does allow you to do is to group objects of different types together, which I think is what you're after with GalaxyOneTwo. Here is more information on how you can do that.
I think you have to have one class Galaxy
, one class SolarSystem
, etc. And yours GalaxyOne
, GalaxyTwo
SolarSystemOne
, SolarSystemTwo
etc. are only different objects instantited from these classes.
class SolarSystem { /* … */ };
class Planet{ /* … */ };
class Moon{ /* … */ };
class Galaxy{ /* … */
public: // Galaxy(...?...){for (...) {read data??; solarSystem.push_back(createSolarSystem(data)); }
void AddSolarSystem(SolarSystem* ss){solarSystem.push_back(ss);}
protected:
std::vector<SolarSystem*> solarSystems;
/* … */
};
....
Galaxy GalaxyOne, GalaxyTwo;
If we have no way to use this simple aproach... Lets see yours:
class GalaxyOneTwo: public GalaxyOne,
public GalaxyTwo,
public PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>{
/* … */
using PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>::solarSystems;
GalaxyOneTwo(){solarSystems.reserve(10);}
};
Here you have three private vectors: (using using
you make it direct accesible)
std::vector<SolarSystemOne* > GalaxyOne::solarSystems;
std::vector<SolarSystemTwo* > GalaxyTwo::solarSystems;
std::vector<SolarSystemOneTwo*> solarSystems; //GalaxyOneTwo::solarSystems;
Is this what you need? Make it protected?
You need to abstract out the common stuff between the 'One' and 'Two' versions of stuff into a set of 'Common' base classes:
class GalaxyCommon {
// all the common stuff between GalaxyOne and GalaxyTwo including
std::vector<SolarSystemCommon *> solarSystems;
...
};
class GalaxyOne : public virtual GalaxyCommon {
// all the stuff that is unique to model One
};
class GalaxyTwo : public virtual GalaxyCommon {
// all the stuff that is unique to model Two
};
class GalaxyOneTwo : public virtual GalaxyOne, public virtual GalaxyTwo {
// should be complete
};
Note the use of virtual
-- required to get properly working multiple inheritance.