[gelöst] Zugriff auf abgeleitete Klasse mit Datentyp der Basisklasse



  • Morgen miteinander,

    ich habe heute eine Frage zum Thema Vererbung, ich habe da nicht wirklich Erfahrung (Schande über mich 😉 ).

    Situation:
    Ich habe eine Basisklasse A, von der 3 weitere Klassen (B,C und D) abgeleitet werden.
    Jede Instanz von B,C und D wird der Klasse "ObjectAdmin" als Pointer übergeben und dort mit dem Datentyp A* gespeichert.

    Beispiel-Code:

    class A{
    protected:
        int myID;
    public:
        void setID(int ID);
        int getID();
    }
    
    class B : public A{
    public:
        B();
        void b();
    }
    
    class C : public A{
    public:
        C();
        void c();
    }
    
    class D : public A{
    public:
        D();
        void d();
    }
    
    class ObjectAdmin{
    private:
        map<int, A*> myObjects; //<ID, Objekt>
    public:
        InstanceAdmin();
        void setInstance(A* object);
        A* getInstance(int ID);
    }
    

    Problem/Frage:
    Ich möchte jetzt über die ID ein Objekt von ObjectAdmin bekommen und die entsprechende Funktion der abgeleiteten Klasse aufrufen (also b(), c() oder d() ).
    Wenn ich es richtig verstehe muss ich dazu ja das Objekt erstmal wieder zum entsprechenden Typ casten, aber wie mache ich das und ist das überhaupt möglich?
    Funktionsnamen usw. sind bekannt, nur beim Cast weiß ich nicht weiter.
    Die Funktionen der abgeleiteten Klassen sind leider so verschieden, dass es mir nicht wirklich weiterhilft, sie in die Basisklasse zu packen und dadurch abzuleiten.

    Gibt es vielleicht eine bessere/elegantere Möglichkeit die Funktionen aufzurufen?
    (Ich weiß, ich kann ein struct mit einem template für den Klassenpointer erstellen, in der map speichern und über ein Funktionstemplate das Objekt mit dem richtigen Datentyp zurückgeben, das ist Plan B 😉 ).

    Ich hoffe ihr könnt mir weiterhelfen.

    Viele Grüße
    Cherup



  • Wenn du in die Basisklasse eine virtuelle Funktion packst, kann sie in den abgeleiteten Klassen überschrieben werden und dadurch mit eigenen Inhalt gefüllt werden. Ein Aufruf der Funktion über einen Basisklassenzeiger ruft die entsprechende Funktion der abgeleiteten Klasse auf.



  • Danke für die Antwort,
    nur leider hilft mir das nicht weiter.
    Ich weiß, dass ich so auf gleichartige Funktionen zugreifen kann, auf diese Weise sind schon ein paar Funktionen implementiert.

    Das Problem ist, das es sehr verschiedene Funktionen sind, auf die ich zugreifen möchte. Die eine baut mir eine neue Klasse, eine weitere gibt mir eine map zurück und die letzte setzt ein Flag.
    Bei 5-10 unterschiedlichen Funktionen pro Klasse, die ich so aufrufen möchte, wird es mir zu unübersichtlich für jeweils 3 den gleichen Funktionsnamen zu haben, der nur in wenigen Fällen die richtige "Beschreibung" der Funktion angibt.
    Zudem gibt es eben in der einen Klasse nur 5 individuelle Funktionen, bei einer anderen 10.

    Daher hatte ich auch in der Problembeschreibung

    Cherup schrieb:

    Die Funktionen der abgeleiteten Klassen sind leider so verschieden, dass es mir nicht wirklich weiterhilft, sie in die Basisklasse zu packen und dadurch abzuleiten.

    geschrieben.

    Bis auf die ID, ein paar Variablen und die dazu passenden get- und set-Funktionen in der Basisklasse haben die abgeleiteten Klassen nichts miteinander gemeinsam.

    Viele Grüße

    Cherup

    Edit:
    Eine Möglichkeit, über eine virtuelle Funktion auf die entsprechenden Funktionen zuzugreifen wäre natürlich eine "selectFunction"-Funktion, der ich mit einen Parameter die aufzurufende Funktion mitteile. Das Problem ist dann an sich nur, wie ich die Parameter-Liste an die aufzurufende Funktion übergebe...



  • Wenn my_A_Ptr in Wahrheit vom Typ B ist, wäre nach dem folgenden Cast ...

    B* my_B_Ptr = dynamic_cast<B*>(my_A_Ptr);
    if(my_B_Ptr != nullptr)
    {
      my_B_Ptr->MySpecialBFoo();
    }
    

    der Pointer my_B_Ptr != nullptr.

    Dynamic_casts sollte man wenn möglich vermeiden, wenn ich das hier im Forum richtig mitbekommen habe, da sie
    a) wohl nicht gerade die flottesten Casts sind
    b) evtl. auf einen Design-Fehler schliessen lassen
    c) hat man gegebenenfalls 1000 Stellen mit dynamic_casts und man je nach dem elendig langen if-nullptr-Abfragen im Code hat.

    Aber technisch möglich wäre es so herauszubekommen, von welchem Typ my_A_Ptr halt wirklich ist um ihn halt auch direkt zu casten.



  • Ok,
    Ich denke dynamic_cast ist so ziemlich genau das, was ich brauche.
    Auch das Problem, das man elendig viele nullpointer-Abfragen hat müsste sich durch eine virtuelle Funktion in den Griff bekommen lassen.
    Ich nutze eine zusätzliche Variable in den abgeleiteten Klassen, in der die "Art" des abgeleiteten Objekts steht und frage sie über eine virtuelle Funktion ab.
    Dadurch kann ich über eine switch-case-Anweisung direkt in den passenden Typ casten 🙂

    Ich werds mal ausprobieren und hier schreiben, obs geklappt hat.

    Viele Grüße
    Cherup



  • So,
    scheint zu laufen, zumindest gibts noch keine Fehler 😉

    Ich habe das so gelöst, dass ich eine Variable für einen Wert für den entsprechenden Datentyp in die Basisklasse gepackt habe und dort auch eine ganz normale get-Methode geschrieben habe. In den Konstruktoren der Klassen B,C und D wird die Variable dann gesetzt.
    Dadurch kann ich den Datentyp vor dem Casten abfragen und dann mit einem static_cast entsprechend casten. dynamic_cast funktionierte leider nicht, weil die Basisklasse keine Polymorphie unterstützt.

    Soweit so gut, das problem ist wohl gelöst 🙂

    Über weitere Anregungen und Verbesserungsvorschläge würde ich mich freuen.

    Viele Grüße
    Cherup



  • Cherup schrieb:

    ... weil die Basisklasse keine Polymorphie unterstützt.

    Und somit auch keinen virtuellen Destruktor? Denk daran, dass ein 'delete basis_pointer;' nur den Destruktor der Basisklasse aufruft. Ein ungewöhnliches Design und sehr gefährlich.



  • Naja, aktuell werden zur Laufzeit keine Instanzen gelöscht, es werden bestenfalls Pointer gelöcht. Ich bin noch relativ neu in der Vererbung, habs bis jetzt noch nicht wirklich gebraucht. Ich kann Klassen ableiten und virtuelle Funktionen erstellen, zu viel mehr reichts nicht. Mit abstrakten Klassen habe ich mich noch nicht wirklich beschäftigt (Wenn ichs richtig verstanden habe, unterstützen nur abstrakte Klassen Polymorphie).
    Kommt aber noch wenn ich meinen Code (oder teilweise besser Kot, wenn ich mir das manchmal so anschaue... 😃 ) aufräume, sicher mache und gegebenenfalls optimiere.

    Danke für den Hinweis


Anmelden zum Antworten