简体   繁体   中英

Guidance in creating design for multiple-inheritance composite classes in c++

I intend this question to be a more generalized question relating to my question found at the following link:

Solving design involving multiple inheritance and composite classes in c++

I am working with data sets related to Galaxies. The data about each galaxy will contain information about a galaxie's solar systems, each solar systems planets and each planets moons.

The Composite Requirement:

From this alone I imagine that I need to use composite class design where I create a class for the galaxy, the solar systems, the planets and the moons. The galaxy class will contain member container variables which contain pointers to solar systems, planets and moons in addition to the appropriate member getter and setter functions for those container variables. The solar system would have a similarly designed member container variables containing pointers to the contained planets and moons with the getters and setters, and so forth with the planets as well.

The Multiple-Inheritence Requirement:

The types of input data that I use for each of these classes is not constant. At times I have data of type 1 and other times perhaps data of type 2. The different kinds of data that I have for any given project may change as time goes on. In order to avoid having a monsterously growing galaxy class which gets new member variables and functions for each not type of data available for each project as well all of the old (and possibly unused in the current project) I want to break the galaxy, solarSystem, planet and moon classes up into related classes each specialized to deal with a certain set of data.

Thus, if I consider two of the possible data sets available to me me, data1 and data2, I may choose to create specific versions of each class for each data set.

I like this approach because if I have a new project which requires the combination of data1 and data2 I can create new classes for the galaxy, solarySystem, planet and moon classes that inherit from both of the relevent types before. Something like the following.

class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo { /* . . .  */ };
class SolarSystemOneTwo: public SolarSystemTwo, public SolarSystemOne{ /* . . . */};
class PlanetOneTwo: public PlanetTwo, public PlanetOne{ /* . . . */ };
class MoonOneTwo: public MoonTwo, public MoonOne{ /* . . . .*/};

This gives me access to all of the veriables and methods for dealing with data1 and data2 AND I can then further define variables and methods for dealing with new properties that arise out of the combination of data1 and data2.

The Problem:

Each of these design ideas, the composite requirement and the multiple-inheritence requirement have worked well on their own for me. But, I would really like to use both. The difficulty in using both is that those container variables within GalaxyOne that give it access to the pointers of SolarSystemOne are of no use to GalaxyOneTwo because the types of pointers in SolarSystemOne do not give access to the member functions of SolarSystemOneTwo.

Possible Solutions:

Template Base Class- Make a template base class PrimitiveGalaxy, PrimitiveSolarSystem, PrimitivePlanet, PrimitiveMoon which contain all of the container variables and relevant getters and setters from which all further classes inherit. This is the approach I used in the link posted above, and its problems can be found there.

Virtual Base Class- It has been proposed that I create a base class which contains all of the shared functions across all kinds of Galaxies, SolarSystems, Planets and Moons. This would include container variables to the relevant pointers as well as their getters and setters. By doing this the pointers could be used to point to the base class of each type and so long as the base type contained virtual functions for all necessary later defined functions, then I could avoid casting my pointers to the more complex types.

My concern for this approach is that it not only requires the writing of virtual functions in the base class for every new function in derived classes but also that not every derived class will define each virtual function in the base class.

Thus far, the above possible solution is the only one I currently understand well enough to post.

I want a solution that allows for flexible code that does not require complicated syntax and that does not require an every growing and unmanageable series of very large class definitions. My projects regularly include new kinds of data so I want to be able to easily create new parsers for this new data and readily be able to include the data into my various projects using the Galaxy, SolarSystem, Planet and Moon classes.

I was able to solve my problem by using an abstract base class. The abstract base class contains all of my container variables and appropriate getter and setter variables. In addition, the abstract base class defines abstract methods for all methods that will be used in any derived class. These methods are surrounded by preprocessor directives that only include those virtual functions if the appropriate header file is also included that defines said functions, this prevents further abstract classes.

class Galaxy{
    protected:
       std::vector<SolarSystem*> solarSystems;
    public:
       void addSolarSystem(SolarSystem*);
#ifdef GALAXYONE
virtual void aGalaxyOneMethod()=0;
#endif

#ifdef GALAXYTWO
virtual void aGalaxyTwoMethod()=0;
#endif

#ifdef GALAXYONETWO
virtual void aGalaxyOneTwoMethod()=0;
#endif

enter code here

};

GalaxyOne.h

#define GALAXYONE
class GalaxyOne{
    protected:
        /*Private Variables for GalaxyOne*/
    public:
        void aGalaxyOneMethod(); //No longer abstract
};

GalaxyTwo.h

#define GALAXYTWO
class GalaxyTWO{
    protected:
        /*Private Variables for GalaxyTwo*/
    public:
        void aGalaxyTwoMethod(); //No longer abstract
};

GalaxyOneTwo.h

#define GALAXYONE
#define GALAXYTWO
#define GALAXYONETWO
class GalaxyOneTwo: virtual public GalaxyOne, virtual public GalaxyTwo{
    protected:
        /*Private Variables for GalaxyOneTwo*/
    public:
        void aGalaxyOneTwoMethod(); //No longer abstract
};

This scheme allows one to create an object of type GalaxyOneTwo and store it in a pointer of Galaxy and still have access to the appropriate functions. A similar strategy is used with SolarSystems, Planets and Moons

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM