0

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.

Community
  • 1
  • 1
PhiloEpisteme
  • 857
  • 3
  • 8
  • 19
  • If you really wish to use this multiple inheritance model, your only choices are 1. cast or 2. within `GalaxyOne` only use containers containing `SolarSystemOneTwo` – Dark Falcon Feb 27 '13 at 20:19
  • I am not set on multiple inheritance for any reason other than it is what I have the best handle on. Could you please expand upon how I could do this with casting? I am not very familiar with it. – PhiloEpisteme Feb 27 '13 at 20:36
  • @vckngs7 Is this question really different from your earlier one? – jogojapan Feb 27 '13 at 20:53
  • I feel that they are related by different. I am asking here how to better design my program. My other question is about how to fix a specific implementation. – PhiloEpisteme Feb 27 '13 at 21:08
  • "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." --- this statement seems to be conjured out of thin air. Can you show it with a concrete code example? – n. m. could be an AI Mar 01 '13 at 17:23
  • I think your problem lies not in the design of the interfaces for your Galaxies and so on, but on the design of your interface to your __data__. Maybe you would get more helpful answers if you would post more details about your (existing and expected) data instead. – Fozi Mar 01 '13 at 17:45
  • @n.m. This surely was not conjured out of thin air. I was able to use said method to solve my problem but it did pose those problems. If I have abstract base class class0, two directly derived classes class1 and class2 and then the multiple inherited derived class, class12. Those methods which will be used in class12 are not defined in class1 or class2 and so they cannot be made virtual in class0 else tokens of class1 and class2 would not be permitted because said methods would be purely abstract. My solution was to use preprocessor directives to alter the virtual abstract base appropriately. – PhiloEpisteme Mar 04 '13 at 19:17
  • @fozi What exactly do you mean by the interface with my data? – PhiloEpisteme Mar 04 '13 at 19:18
  • @vckngs7 I mean that your Galaxy objects are not the data, they use the data. DataType1 is your data and DataType2 as well, and if you expect your objects to be able to use both and even future ones then you should think about a generic interface to your data instead of trying to shoehorn your data into your other objects. – Fozi Mar 04 '13 at 20:37
  • Why do you want to have these methods in class0 in the first place? Are they called via class0 pointers? If they are, how do you guarantee that this pointer does not point to a class1 or class2 object? – n. m. could be an AI Mar 04 '13 at 20:50
  • @fozi Mostly what I want to be able to do is store the data from DataSet1 into Class1 and all derived classes of class1. Some of the data that I generate is synthetic data from DataType1 and DataType2 which is why I have further methods in GalaxyOneTwo which creates this synthetic data from DataType1 and DataType2. I do not know a better way to go about doing this. Do you have a suggestion that I can look into? – PhiloEpisteme Mar 06 '13 at 20:38
  • @n.m. The only methods I truly want in class0 are the getter and setter methods for the container variables. Ex the vector within Galaxy which contains pointers to the SolarSystems. In order to allow for these pointers to work with derived SolarSystem types I had to make class0 an abstract base class with all derived methods as undefined virtual methods. – PhiloEpisteme Mar 06 '13 at 20:41

1 Answers1

1

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

PhiloEpisteme
  • 857
  • 3
  • 8
  • 19