Problem mit abstrakten Klassen



  • Hallo,

    ich habe eine abstrakte Klasse A mit einer virtual = 0-Funktion do() und zwei Kinder B1 und B2, die do() überschreiben.

    Jetzt möchte ich einen vector<A> haben, aber da kommt die Fehlermeldung "cannot instantiate abstract class due to following members: ..."

    Was tun?



  • mach einen vector<A*>



  • Danke.

    Das ist vmtl auch performancemäßig das Beste?



  • hmmmmmmmm schrieb:

    Das ist vmtl auch performancemäßig das Beste?

    Nein, sofern du normales new verwendest. Aber ich weiss nicht, ob sich ein anderer Allokator für dich lohnt. Ich habe eher das Gefühl, du brauchst die Performance nicht so dringend.

    Schlimmer bei std::vector<A*> ist die manuelle Speicherverwaltung und damit auch die fehlende Exceptionsicherheit. Kann sein, dass das bei dir vertretbar ist. Falls du Boost benutzt, kannst du andernfalls z.B. die spezialisierten PointerContainer benutzen.



  • kommt drauf an...
    jedenfalls ist es die einzige Möglichkeit polymorphe vectoren/listen anzulegen, die mir bekannt ist.

    denk aber dran, dass du die objekte dann auch mit new anlegen musst und am ende per delete wieder freigeben musst.

    sicherer ist (sofern dein Compiler schon TR1 unterstützt :=) ) dies:

    #include <vector>
    #include <memory>
    
    std::vector<std::tr1::shared_ptr<A> > vA;
    

    bei C++0x wandert shared_ptr aus std::tr1 nach std.
    falls dein Compiler kein TR1 dabei hat, geht das auch mit boost:

    // shared ptr
    #include <vector>
    #include <boost/shared_ptr.hpp>
    
    std::vector<boost::shared_ptr<A> > vA1;
    
    // scoped_ptr
    #include <boost/scoped_ptr.hpp>
    
    std::vector<boost::scoped_ptr<A> > vA2;
    

    scoped_ptr ist nicht so flexibel wie shared_ptr, dafür aber performanter.
    Zu den genauen Unterschieden empfehle ich dir die boost-Doku zu lesen.

    Ob scoped_ptr auch im TR1 enthalten ist, weiß ich auf die Schnelle nicht :p

    jedenfalls musst du bei den Lösungen zwar die Objekte auch wieder mit new anlegen (Polymorphie halt), kannst aber auf die delete's verzichten.

    Prinzipiell ist aber ein roher A* am performantesten, verglichen mit den smart-pointern.



  • Und wie würde ich einen boost::ptr_vector<Base> verwenden?



  • DrakoXP schrieb:

    scoped_ptr ist nicht so flexibel wie shared_ptr, dafür aber performanter.

    Was einem aber hier nichts nützt, weil scoped_ptr keine Kopiersemantik unterstützt und damit zur Speicherung in STL-Containern ausfällt.

    DrakoXP schrieb:

    Ob scoped_ptr auch im TR1 enthalten ist, weiß ich auf die Schnelle nicht :p

    Nein, leider nicht.

    DrakoXP schrieb:

    Prinzipiell ist aber ein roher A* am performantesten, verglichen mit den smart-pointern.

    Allerdings muss er nicht unbedingt schneller als die Pointer-Container sein.

    hmmmmmmmmm schrieb:

    Und wie würde ich einen boost::ptr_vector<Base> verwenden?

    Grundsätzlich sehr ähnlich wie einen std::vector<Base> . Der Zeiger wird dir automatisch dereferenziert, hauptsächlich beim Einfügen musst du einen Zeiger mit new übergeben. Für Genaueres solltest du die Boost-Doku anschauen.



  • scoped_ptr soll in TR2.
    shared_ptr ist auch in boost.



  • Nexus schrieb:

    hmmmmmmmmm schrieb:

    Und wie würde ich einen boost::ptr_vector<Base> verwenden?

    Grundsätzlich sehr ähnlich wie einen std::vector<Base> . Der Zeiger wird dir automatisch dereferenziert, hauptsächlich beim Einfügen musst du einen Zeiger mit new übergeben. Für Genaueres solltest du die Boost-Doku anschauen.

    Wird das Objekt, auf das der Zeiger zeigt, automatisch gelöscht, wenn der ptr_vector zerstört wird?



  • hmmmmmmmmm schrieb:

    Wird das Objekt, auf das der Zeiger zeigt, automatisch gelöscht, wenn der ptr_vector zerstört wird?

    Ja, das ist ja einer der grossen Vorteile.



  • Wie realisiere ich mit einem

    ptr_vector<T>
    

    folgendes: Suche eine Folge von drei aufeinander folgenden Elementen des vectors, die in dem vector nochmals in dieser Reihenfolge auftritt?

    also z.B: 12347896541234435643



  • Naja. Der naive Ansatz ist ja wie folgt. Fang einfach mal mit den ersten 3 (oder 4?) Elementen an und dann überprüf dafür die nächsten 3 Elemente und schiebst den um 1 weiter je Iteration. Das machst du dann für jeden Startpunkt. Das gibt O(n^2).

    Man könnte aber auch wie folgt vorgehen: Zuerst alle Elemente in ein Objekt packen und eine verknüpfte Liste draus machen. Dann die Knoten den Werten entsprechend sortieren (verknüpfungen nicht ändern) und dann kannst du das erste Element nehmen und dann die nächsten 3 Elemente betrachten. Dann nimmst du das nächste Element in der sortieren Liste, welches natürlich die nächste Folge mit dem gleichen Anfang ist und überprüfst dort ob die nächsten 3 Zahlen gleich der den ersten sind. Wenn du nur an der ersten solchen Folge interessiert bist, dann geht das in O(nlog(n)).


Log in to reply