Design solution using multiple inheritance and compound classes in C ++

I struggled with this design problem for a while. I will do my best to explain what I'm trying to do, and the different approaches that I saw, what I'm trying and why.

I work in a scientific computing environment where I repeatedly come across the same types of objects. Imagine a galaxy that contains solar systems, every solar system contains planetary systems, and every planetary system contains moons. To this end, I consider the situation a β€œsituation”, and therefore I used composition to give the galaxy access to its solar systems, and each solar system gets access to planetary systems that have access to their moons: each category being its own class.

It often happens that the various problems I'm working on contain different types of data about these objects. And, when different types of data are available, I can do certain things with my objects. So, when I have data type 1 available to me, I create the following classes

class GalaxyOne { /* … */ }; class SolarSystemOne { /* … */ }; class PlanetOne{ /* … */ }; class MoonOne{ /* … */ }; 

And when I have data type 2 available to me, I create

 class GalaxyTwo { /* … */ }; class SolarSystemTwo { /* … */ }; class PlanetTwo{ /* … */ }; class MoonTwo{ /* … */ }; 

The complex aspects of each class are considered using container variables, such as vectors that contain pointers to the contained classes. For example, in every class of the Galaxy one could find.

 class GalaxyTwo{ /* … */ protected: std::vector<SolarSystemTwo*> solarSystems; /* … */ }; 

The difficulty arises when I want to combine classes into classes of a higher order.

 class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo{ /* Additional methods */ }; 

However, this creates an ambiguity problem in the solarSystems vector, because GalaxyOneTwo will have a version from GalaxyOne and GalaxyTwo. In addition, inherited vectors contain pointers to objects that are not of the type of SolarSystemOneTwo that is required. So, I thought I could create a template class that inherits all my objects, from where I put all my container variables.

 template<MoonT,PlanetT,SolarSystemT> class PrimitiveGalaxy { private: std::vector<SolarSystemT*> solarSystems }; class GalaxyOne: public PrimitiveGalaxy <MoonOne,PlanetOne,SolarSystemOne>{ /* No longer defining any container variables for composition */ }; 

This approach is very well suited for those fundamental types of Galaxy (GalaxyOne and GalaxyTwo). However, whenever I try to create a combined type of galaxy, I get all kinds of ambiguities.

 class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo, public PrimitiveGalaxy<MoonOneTwo,PlanetOneTwo,SolarSystemOneTwo>{ /* … */ }; 

I get ambiguity if I use solarSystems in any method defined in GalaxyOneTwo because it is defined three times, once through each legacy version from GalaxyOne and GalaxyTwo, and the third time through GalaxyOneTwo.

I can get rid of this ambiguity by being specific and using

PrimitiveGalaxy :: SolarSystems

each time refer to its own vector, but this is undesirable because it requires a lot of extra input and syntax.

I have considered using friendships between each type of galaxy and a primitive galaxy, but this requires a similar level of detailed writing.

I have a suspicion that namespaces may simplify my code entry, but I'm not sure how to define a namespace in such a way that in the namespace defined for GalaxyOneTwo that any reference to solarSystems is a reference to PrimitiveGalaxy :: SolarSystems

Edit:

Please note that the only difference between GalaxyOne and GalaxyTwo is NOT the type of the class contained in solarSystems. There are many differences because each class deals with different data related to the galaxy. Thus, I create different classes that will have different state variables, getters and setters for these state variables and methods for calculating and printing data. solarSystems is an example of a function that gives me problems, so this is what I described here. When GalaxyOneTwo is created, it will use the same data that is used for GalaxyOne and GalaxyTwo, and therefore I want to inherit all their variables and methods. And since data can be combined in different ways, I need to create new methods for this in GalaxyOneTwo. These are some of the many differences that make me use inheritance. That being said, these are container variables that allow me to create compositions that give me problems. Within each SolarSystem class, a similar vector will exist, giving them access to their planets, etc. Etc.

Edit:

For a question specifically dedicated to my design philosophy here in general (as opposed to those questions about trying to solve my current design attempt), see the following link: Design Guide for Composite Classes with Multiple Inheritance in C ++

+7
source share
4 answers

Perhaps you can modify data models to implement a component-based component. Each component can contain the same state information that you specified for different types. And you can 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 various types of solar systems or galaxies to create special cases and fill in virtual function calls

 class CoolSolarSystem : public SolarSystem { // Special variables // Fill in the virtual function void sharedSolarSystemFunction(); }; 

Then you can fill containers inside different base types with pointers to special types. You should be able to avoid reverting back to a special type if the virtual function calls a handle to this information.

+1
source

I think you should have one class Galaxy , one class SolarSystem , etc. And your GalaxyOne , GalaxyTwo SolarSystemOne , SolarSystemTwo , etc. - these are just different objects created 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 do not have the opportunity to use this simple aproach ... Let's look at 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 available)

 std::vector<SolarSystemOne* > GalaxyOne::solarSystems; std::vector<SolarSystemTwo* > GalaxyTwo::solarSystems; std::vector<SolarSystemOneTwo*> solarSystems; //GalaxyOneTwo::solarSystems; 

That's what you need? Make it secure? enter image description here

+2
source

You need to abstract the general material between the versions of "One" and "Two" into a set of base classes "General":

 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 that using virtual is required for multiple inheritance to work properly.

0
source

So, if I understand your question correctly:

  • There are several types of galaxies that cannot have anything in common between them.
  • The same goes for the solar and planetary systems.
  • You would like to combine the collections of these different types and still have full access to the main methods for this type.

This sounds like a case for boost :: any

So, now your Galaxy:

 #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... }; 

Of course, this does not actually do anything, but allows you to group them. To do something useful (call a method), you still have to discover the type, apply it to that type, and then run the code you need.

However, this allows you to group objects of different types together, and I think you use GalaxyOneTwo after that. Here's more information on how you can do this.

0
source

All Articles