Kopierkonstruktor und Polymorphie



  • Hallo zusammen

    Ganz blöde Frage, aber irgendwie komme ich einfach nicht zu einer Lösung. Ich hab zwei Klassen A und davon abgeleitet B. Jz mach ich mir eine verkettete Liste, wo ich allerdings mit List::add(A const&) jeweils nur eine Kopie in die Liste und nicht das originale Element einfügen möchte. Jz kann es sein, dass ich auch Instanzen von B in meine Liste hinzufügen möchte. Wenn ich in List::add() nun den Kopierkonstruktor aufrufe, weiß der Compiler zur Compile-Time ja nicht, welches Objekt da reingehört, und welchen Kopierkonstruktor er aufrufen soll. (bzw er ruft einfach den von A auf). Wie löst man sowas?

    Vl noch kurz und bündig das ganze in Code:

    class A {
        // ...
        A( A const&);
    }
    
    class B : public A {
        // ...
        B( B const&);
    }
    
    // ...
    
    void List::add(A const& A_) {
        // make a copy
        A ourCopy( A_ );
    }
    
    int main() {
        // ...
        A a;
        B b;
        list.add(a);
        list.add(b); // <- hier wird eben nur der "A-Teil" von B kopiert
    }
    

    Als eine Möglichkeit fällt mir ein eine virtuelle copy-Funktion in A zu scrheiben, die in B auch implementiert wird, und dass List::add() eben diese Funktion aufruft, aber ghet das nicht etwas schöner?

    Danke auf jeden Fall!



  • Nein, das geht nicht.
    Erstell die Objekte mit new und speichere die Zeiger in der Liste.



  • In der Liste speichere ich natürlich nur die Zeiger auf die Objekte. Aber eben Zeige auf A. Und was wenn ich nun eine Instanz von B in List::add() übergeben bekomme...



  • blitzmaster schrieb:

    In der Liste speichere ich natürlich nur die Zeiger auf die Objekte. Aber eben Zeige auf A. Und was wenn ich nun eine Instanz von B in List::add() übergeben bekomme...

    Das sieht hier aber ganz anders aus.

    void List::add(A const& A_) {
        // make a copy
        A ourCopy( A_ );
    }
    

    Wo speicherst du irgendwas?



  • Ja das stimmt, das habe ich etwas ungenau/falsch skizziert:

    void List::add(A const& A_) {
       // ...
       A* ourCopy = new A( A_ );
       // den pointer A* dann an den richtigen Knoten weitergeben
    }
    


  • Solange du nur Zeiger oder Referenzen auf die übergebenen Objekte speicherst, brauchst du dir keine Gedanken darüber machen, ob das jetzt ein A oder ein B (oder etwas anderes) ist. Aber natürlich mußt du dich dann darum kümmern, daß die Objekte selber länger überleben als die Verweise, die du auf sie angelegt hast.

    Wenn die Liste Kopien der übergebenen Objekte speichern will, muß sie das über Zeiger erledigen und sich auch möglichst selber um die Verwaltung kümmern. Da kann dann eine virtuelle clone()-Methode in der Klasse hilfreich sein, um eine komplette Kopie zu erzeugen.
    Eine Alternative wäre noch Compilezeit-Polymorphie mittels Templates:

    template<typename T>
    List::add(T const& obj)
    {
      A* ptr = new T(obj);//das sollte nur für A und Nachkommen übersetzen
      ...
    }
    


  • Ja, Templates habe ich auch schon gedacht... Aber das wollte ich vermeiden... Ich werds jetzt einfach mit einer virtuellen copy-funktion machen. Ich dachte nur vielleicht geht das irgendwie eleganter, aber na gut. Danke euch beiden auf jeden Fall!



  • blitzmaster schrieb:

    Ich werds jetzt einfach mit einer virtuellen copy-funktion machen. Ich dachte nur vielleicht geht das irgendwie eleganter, aber na gut.

    Das ist die übliche Art es zu machen.
    Elegantere Möglichkeit ist mir keine bekannt.


Anmelden zum Antworten