Rozwiązywanie projektu obejmującego wielokrotne klasy dziedziczenia i złożone w c ++

Od jakiegoś czasu zmagam się z tym problemem projektowym. Zrobię, co w mojej mocy, aby wyjaśnić, co próbuję zrobić, i różne podejścia, które widziałem, co próbuję i dlaczego.

Pracuję w naukowym środowisku komputerowym, gdzie wielokrotnie zajmuję się tymi samymi obiektami. Wyobraź sobie galaktykę, która zawiera układy słoneczne, każdy układ słoneczny zawiera układy planetarne, a każdy układ planetarny zawiera księżyce. W tym celu uważam sytuację za sytuację „ma” i dlatego użyłem kompozycji, aby dać galaktyce dostęp do jej systemów słonecznych, a każdy układ słoneczny ma dostęp do systemów planetarnych, które mają dostęp do ich księżyców: każda kategoria będąc własną klasą.

Często zdarza się, że różne problemy, nad którymi pracuję, zawierają różne typy danych o tych obiektach. W miarę udostępniania różnych typów danych mogę wykonywać pewne rzeczy za pomocą moich obiektów. Więc kiedy mam dla mnie typ danych 1, tworzę następujące klasy

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

A kiedy mam dla mnie typ danych 2, tworzę go

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

Złożone aspekty każdej klasy są rozwiązywane za pomocą zmiennych kontenerowych, takich jak wektory, które zawierają wskaźniki do zawartych klas. Na przykład w każdej klasie Galaxy można by znaleźć.

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

Trudność pojawia się, gdy chcę połączyć klasy w klasy wyższego rzędu.

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

Stwarza to jednak problem niejednoznaczności w wektorze solarSystems, ponieważ GalaxyOneTwo miałoby wersję z GalaxyOne i GalaxyTwo. Ponadto wektory, które dziedziczy, zawierają wskaźniki do obiektów, które nie są typu SolarSystemOneTwo, które byłyby wymagane. Pomyślałem, że mogę utworzyć klasę szablonów, którą odziedziczą wszystkie moje obiekty, z której umieściłem wszystkie moje zmienne kontenerowe.

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 */
};

Takie podejście działa bardzo dobrze dla tych podstawowych typów Galaxy (GalaxyOne i GalaxyTwo). Jednak za każdym razem, gdy próbuję stworzyć połączony typ galaktyki, otrzymuję wszelkiego rodzaju dwuznaczności.

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

Dostaję dwuznaczność, jeśli używam solarSystems w dowolnej metodzie zdefiniowanej w GalaxyOneTwo, ponieważ jest ona zdefiniowana trzy razy, raz w każdej odziedziczonej wersji z GalaxyOne i GalaxyTwo, a trzeci raz w GalaxyOneTwo.

Mogę pozbyć się tej niejednoznaczności, będąc konkretnym i używając

PrimitiveGalaxy :: solarSystems

za każdym razem, aby odwołać się do właściwego wektora, ale nie jest to pożądane, ponieważ wymaga DUŻO dodatkowego pisania i składni.

Rozważyłem użycie przyjaźni między każdym typem galaktyki a prymitywną galaktyką, ale wymaga to podobnego poziomu szczegółowego pisania.

Mam przeczucie, że przestrzenie nazw mogą uprościć pisanie kodu, ale nie jestem pewien, jak zdefiniować przestrzeń nazw w taki sposób, że w przestrzeni nazw zdefiniowanej dla GalaxyOneTwo, że jakiekolwiek odniesienie do solarSystems jest odniesieniem do PrimitiveGalaxy :: solarSystems

Edytować:

Należy pamiętać, że jedyna różnica między GalaxyOne a GalaxyTwo NIE jest typem klasy zawartej w solarSystems. Istnieje wiele różnic, ponieważ każda klasa zajmuje się różnymi danymi dotyczącymi galaktyki. Dlatego tworzę różne klasy, które będą miały różne zmienne stanu, pobierające i ustawiające dla tych zmiennych stanu oraz metody obliczania i drukowania danych. solarSystems jest przykładem funkcji, która sprawia mi problemy, dlatego opisałem to tutaj. Kiedy GalaxyOneTwo zostanie utworzone, użyje tych samych danych, które są używane dla GalaxyOne i dla GalaxyTwo, dlatego chcę dziedziczyć wszystkie ich zmienne i metody. A ponieważ dane można łączyć na różne sposoby, muszę stworzyć nowe metody do tego w GalaxyOneTwo. Oto niektóre z wielu różnic, które prowadzą mnie do dziedziczenia. To powiedziawszy, to zmienne kontenerowe pozwalają na składanie problemów. W każdej klasie systemu solarnego będzie istniał podobny wektor dający im dostęp do ich planet, i tak dalej, i tak dalej.

Edytować:

W przypadku pytania specjalnie poświęconego mojej filozofii projektowania tutaj w ogóle (w przeciwieństwie do tego pytania, które kładzie nacisk na próbę rozwiązania mojej obecnej próby projektowania), zobacz poniższy link:Wskazówki dotyczące tworzenia projektu dla klas złożonych z wieloma dziedziczeniami w c ++

questionAnswers(4)

yourAnswerToTheQuestion