Pointer auf Basisklasse, aber welche Kindklasse ist es?



  • Ich habe folgendes Szenario:

    class A
    {};
    
    class B : public A
    {};
    
    class C : public A
    {};
    
    int main(int argc, char** argv)
    {
    	B b;
    	A* pA = &b;
    
    	//ist pA nun Kindklass B oder C?
    
    	return 0;
    }
    

    Wie kann man möglichst elegant an so einer Stelle herausfinden, ob pA der Kindklasse B angehört?

    Ich sehe da zwei Möglichkeiten:
    1. Ich füge der Basisklasse eine rein virtuelle Funktion getClassType() hinzu, die dann in den Kindklassen unterschiedliche integer-Werte zurückgeben.
    2. Wiederum virtuelle Funktionen an der Basisklasse isB() und isC() die in der Basisklasse alle 0 zurückgeben, die jeweilige Kindklasse überschreibt die Funktion und gibt 1 zurück.

    Bei Idee 1 sehe ich das Problem, dass ausversehen zwei Klassen den selben Wert zurückgeben könnten.
    Bei Idee 2 kann das selbe passieren, es werden bedeutend mehr Funktionen benötigt und dann kann eine Klasse sich auch noch als mehrere outen. Also eigentlich noch schlimmer. (Außer ich will eine Klasse wieder von zwei Kindklassen ableiten, was aber nicht der Fall ist.)

    Seht ihr noch andere Lösungsansätze? Oder bietet C++ gar selbst solche Funktionen?
    Oder gehe ich mein Problem komplett falsch an?



  • Bei sowas sollte man sich immer erstmal fragen, wozu man das braucht. Ansonsten: dynamic_cast .



  • Ich soll eine Verwaltung von Büchern und Zeitschriften schreiben, die beide von Literatur abgeleitet sind.

    Jetzt wollte ich diese gemeinsam in einer Liste zusammenfassen und dem Benutzer anzeigen. Sollen sie aber bearbeitet werden, dann müsste ich hier eine Unterscheidung treffen können, da andere Daten verändert werden können.

    Diese Anzeige wollte ich nicht in die Klassen stecken, da ich die Oberfläche gerne vom Gerüst darunter trennen wollte.



  • knuddelvieh schrieb:

    Ich soll eine Verwaltung von Büchern und Zeitschriften schreiben, die beide von Literatur abgeleitet sind.

    Jetzt wollte ich diese gemeinsam in einer Liste zusammenfassen und dem Benutzer anzeigen. Sollen sie aber bearbeitet werden, dann müsste ich hier eine Unterscheidung treffen können, da andere Daten verändert werden können.

    Diese Anzeige wollte ich nicht in die Klassen stecken, da ich die Oberfläche gerne vom Gerüst darunter trennen wollte.

    Wenn es aus Sicht der Bearbeitung unterschiedliche Typen sein sollen, dann solltest Du dafür auch unterschiedliche Listen nehmen.



  • dann willst du also, abhängig davon, welche Kindklasse hinter pA steckt eine andere Funktion ausführen?

    1. virtuelle Funktionen in Basisklasse:
    class Base 
    {
    public:
      virtual void bearbeiten() = 0;
    };
    
    class Kind1 : public Base
    {
      virtual void bearbeiten() { /* hier code zum Bearbeiten von Kind1 */ }
    };
    
    class Kind2 : public Base
    {
      virtual void bearbeiten() { /* hier code zum Bearbeiten von Kind2 */ }
    };
    
    int main()
    {
      Kind1 k1;
      Base* pB = &k1;
      pB->bearbeiten();  // hier wird kind1::bearbeiten aufgerufen
    }
    

    2. Du kannst auch das Visitor-Pattern nehmen:

    class Base;
    class Kind1;
    class Kind2;
    class Bearbeiten_Visitor
    {
      public:
      void visit(Kind1* k) { /* Code für Kind1 */ }
      void visit(Kind2* k) { /* Code für Kind2 */ }
    };
    
    class Base
    {
      public virtual void accept(Bearbeiten_Visitor& v) = 0;
    };
    
    class Kind1 : public Base
    {
      public:
      virtual void accept(Bearbeiten_Visitor& v) { v.visit(this); }
    };
    
    class Kind2 : public Base
    {
      public:
      virtual void accept(Bearbeiten_Visitor& v) { v.visit(this); }
    };
    
    int main()
    {
      Kind1 k1;
      Base* pB = &k1;
    
      Bearbeiten_Visitor bearbeiter;
      pB->accept(bearbeiter);  // hier wird jetzt je nachdem der Code für Kind1 oder Kind2 aufgerufen.
    }
    

    Wenn du aus Bearbeiten_Visitor noch eine Basisklasse IVisitor machst und davon dann deinen Bearbeiter ableitest, kannst du auch andere Besucher erstellen und diese mit der selben MEthode aufrufen.
    siehe auch den Wikipedia-Artikel.

    Aber vielleicht ist dieses Pattern auch ein bisschen Overkill für deine Anwendung 🙂

    Liebe Grüße, Maxi


Log in to reply