list und abstrakte klassen



  • Hallo,

    angenommen ich habe eine abstrakte Klasse Kunde und zwei davon abgeleitete (nicht abstrakte) Klassen Privatkunde und Firmenkunde.

    Jetzt möchte ich eine Liste mit Objekten beider (Privat- und Firmen-) Kunden anlegen. Ist dies mit "list" aus der Standardbibliothek möglich.

    Definiere ich

    list<Kunde> liste
    

    bekomme ich folgende Fehlermeldung: error C2259: 'Kunde': Instanz von abstrakter Klasse kann nicht erstellt werden

    Dieser Fehler tritt in der list.h auf...

    Wie gehe ich hier vor?

    Danke für Tipps



  • In dem Fall mußt du dir in der Liste Pointer halten und nicht die Objekte selbst. Anders gehts nicht.

    list <Kunde *>
    


  • Vielen Dank, funktioniert 🙂



  • Mathias schrieb:

    In dem Fall mußt du dir in der Liste Pointer halten und nicht die Objekte selbst. Anders gehts nicht.

    list <Kunde *>
    

    Referenzen gehen auch.



  • GPC schrieb:

    Referenzen gehen auch.

    Auch auto_ptr "gehen". Erzeugen aber absolut sinnloses verhalten. Die Requirements (Assignable) sind einfach nicht erfüllt.



  • referenzen gehen garnet. spätestens beim auslesen kracht es(wenn nicht schon vorher), weil list dann versucht, ne referenz auf ne referenz zu erstellen...



  • hallo ich hatte die gleiche idee wie dieter33,

    in einer liste sollten sich spezialisierte objekte befinden, die alle eine gemeinsame basisklasse haben. (zb. firmenkunden : kunde, privatkunden : kunde) . beschreibe ich die liste so : list<kunde> und uebergebe der funktion "add(kunde& ein_kunde)" eine referenz, dann macht die stl wohl standardmaessig aus einem privatkunden einen kunden , da sie nur die daten fuer kunde kopiert (stl legt ja immer eine const objektkopie an). dann allerdings bleibt der Polymorphismus auf der strecke. ab dann steht mir nur noch ein objekt vom typ kunde zur verfügung.

    die impl. mit zeigern klappt tadellos, aber die objekte lassen sich nicht mehr mit der std:sort sortieren, da diese ja referenzen auf ein objekt verlangt.

    wie kann ich nun in eine list<kunde> anlegen, wobei sich die objekte in ihrer genauen auspraegung erst zur laufzeit ergeben, diese sortiert halten und dann anschliessend die virtuellen methoden darauf ausführen?

    danke für eure hardcore-minds schon mal im voraus...



  • 7H3 N4C3R schrieb:

    GPC schrieb:

    Referenzen gehen auch.

    Auch auto_ptr "gehen". Erzeugen aber absolut sinnloses verhalten. Die Requirements (Assignable) sind einfach nicht erfüllt.

    😮 auto_ptr gehen, ausser daß sie nicht gehen, ansonsten gehen sie oder wie war das gemeint?

    Also Smart-pointer gehen. Gibt es leider noch nicht in der Standardbibliothek.


  • Mod

    ichbinsnochmal schrieb:

    hallo ich hatte die gleiche idee wie dieter33,

    in einer liste sollten sich spezialisierte objekte befinden, die alle eine gemeinsame basisklasse haben. (zb. firmenkunden : kunde, privatkunden : kunde) . beschreibe ich die liste so : list<kunde> und uebergebe der funktion "add(kunde& ein_kunde)" eine referenz, dann macht die stl wohl standardmaessig aus einem privatkunden einen kunden , da sie nur die daten fuer kunde kopiert (stl legt ja immer eine const objektkopie an). dann allerdings bleibt der Polymorphismus auf der strecke. ab dann steht mir nur noch ein objekt vom typ kunde zur verfügung.

    die impl. mit zeigern klappt tadellos, aber die objekte lassen sich nicht mehr mit der std:sort sortieren, da diese ja referenzen auf ein objekt verlangt.

    wie kann ich nun in eine list<kunde> anlegen, wobei sich die objekte in ihrer genauen auspraegung erst zur laufzeit ergeben, diese sortiert halten und dann anschliessend die virtuellen methoden darauf ausführen?

    danke für eure hardcore-minds schon mal im voraus...

    du kannst ganz normal mit containern von pointer arbeiten, und musst dann lediglich ein selbstgeschriebenes prädikat an die sortierfunktion geben (less würde ja die pointer vergleichen). bequemer (syntaktisch, da die doppelte indirektion in die iteratoren eingebaut ist) und sicherer sind boosts pointer-container - die ganz nebenbei auch über ein einheitlicheres interface verfügen, so dass sie leichter untereinander austauschbar sind.



  • hm...mir sagt selbstgeschriebenes prädikat grad nichts...was meint das? *sonst muss ich morgen mal googlen *



  • std::list hat keine Prädikate. std::set, std::multiset, std::map und std::multimap haben eins. Und selbst da spricht nichts dagegen, Pointer zu vergleichen. Auch da sind keine selbstgeschriebenen Prädikate notwendig.



  • das dachte ich bisher auch und habe mir ein set mit pointern gebastelt. jedoch wird das set nicht sortiert gehalten, da std::set nur mit const Object& diese funktion erfuellen kann, wenn der operator< ueberladen wurde. mit referenzen auf objekte geht das ja auch wunderbar, jedoch fuehrt es zu den oben genannten problem, das der polymorphismus nicht mehr funktioniert. also sind zeiger noetig dachte ich mir und siehe da es funktioniert auch mit den zeigern tadellos, bis auf das set die hinzugefuegten objekte nicht sortiert haelt, da es lediglich die zeiger sortiert haelt! frage: wie sieht eine moegliche sortierung eines sets aus, wenn es als std::set<Kunden*> definiert ist
    und mit
    mySet.insert(new FirmenKunde()) bzw. mySet.insert(new PrivatKunde()) gefuellt werden soll und anschliessend ein Zeiger aus dem Set geholt und
    pKundenZeiger->ausgeben() aufgerufen werden soll , wobei gilt

    virtual void FirmenKunde::ausgeben()
    virtual void PrivatKunde::ausgeben()
    

    mein operator< lautet:

    int Kunde::operator<(Kunde* pKunde)
    {
    return mName < pKunde->mName;
    }
    

    allerdings wird der nie aufgerufen..



  • Du mußt dir schon ein eigenes Vergleichsprädikat für Pointer schreiben und dem Set bekanntgeben:

    bool lower_pkunde(Kunde* l,Kunde* r)
    { return *l<*r; }
    
    map<Kunde*,lower_pkunde> my_map;
    


  • hm, nach praedikaten habe ich schon gegoogelt...allerding verwirrt mich der ausdruck map etwas.

    was meint ein vergleichspraedikat fuer pointer erstellen und dieses dem set bekanntgeben genau.. (das sagt mir leider nicht allzuviel 😕 )



  • ichbinsnochmal schrieb:

    hm, nach praedikaten habe ich schon gegoogelt...allerding verwirrt mich der ausdruck map etwas.

    was meint ein vergleichspraedikat fuer pointer erstellen und dieses dem set bekanntgeben genau.. (das sagt mir leider nicht allzuviel 😕 )

    Du kannst seinem Set beim Initialisieren ein Funktionsobjekt mitgeben dass er zum Vergleichen zweier Einträge in die Liste verwendet. Du musst ein solches Objekt definieren, dass als Parameter zwei Pointer auf die von dir verwendete Klasse und deinen Bedürfnissen zuschneiden.



  • ichbinsnochmal schrieb:

    hm, nach praedikaten habe ich schon gegoogelt...allerding verwirrt mich der ausdruck map etwas.

    Sorry, mein Fehler - das da oben sollte "set<Kunde*,lower_pkunde>" heißen.

    was meint ein vergleichspraedikat fuer pointer erstellen und dieses dem set bekanntgeben genau.. (das sagt mir leider nicht allzuviel 😕 )

    Das heißt, du benötigst eine Funktion, die zwei Kunde* Pointer auf größer vergleichen kann. Da man Operatoren nicht für Pointer überladen kann, brauchst du eine "normale" Funktion - dort oben ist das "lower_pkunde".
    Anschließend kannst du der set mitteilen, daß sie statt op<() deine Vergleichsfunktion verwenden soll, um Schlüssel zu vergleichen.



  • ok, ich glaub zumindest theoretisch weiss ich jetzt bescheid .
    hier folgender code, der nicht kompliliert, aber so habe ich das bis jetzt verstanden...wo ist der haken?

    ...
    
    #include "property.h"
    
    using namespace std;
    #include <vector>
    #include <set>
    #include <iterator>
    #include <algorithm>
    
    #include <iostream>
    
    class PropertyCollection {
      public:
        PropertyCollection (  );
        virtual ~PropertyCollection (  );
    
        bool addElement(Property* property);
        //bool addElement(Property& property);
    
        AbstractProperty* first();
        AbstractProperty* next();
    
        inline int lowerProperty(Property* p1, Property* p2)
        {
                    return p1->mName < p2->mName;
        }
    
    36:     set<Property*, lowerProperty> mSet;
            set<Property*, lowerProperty>::iterator it;
    
    };
    
    #endif
    

    Fehlermeldung:
    propertycollection.h:36: template argument 2 is invalid
    propertycollection.h:36: ISO C++ forbids declaration of mSet' with no type propertycollection.h:37: invalid use of undefined typeclass
    PropertyCollection'

    der eintrag 36: ist nur zur orientierung

    ? muss lowerProperty(..) in die Klasse Property oder PropertyCollection?
    ? wie sieht die deklaration fuer den iterator aus?
    ? wie rufe ich sort auf? sort(mSet.begin(), mSet.end(), lowerProperty) ??



  • ichbinsnochmal schrieb:

    ? muss lowerProperty(..) in die Klasse Property oder PropertyCollection?

    entweder als globale Funktion oder in die PropertyCollection (in letztem Fall jedoch static - normale Member erwarten einen zusätzlichen this-Parameter, der für die set<> zu viel ist)

    ? wie sieht die deklaration fuer den iterator aus?

    Die sieht so richtig aus, wie du es geschrieben hast.

    ? wie rufe ich sort auf? sort(mSet.begin(), mSet.end(), lowerProperty) ??

    Eine set<> brauchst du nicht zu sortieren, die hält die Elemente von sich aus in sortierter Reihenfolge.



  • tntnet schrieb:

    7H3 N4C3R schrieb:

    Auch auto_ptr "gehen". Erzeugen aber absolut sinnloses verhalten. Die Requirements (Assignable) sind einfach nicht erfüllt.

    😮 auto_ptr gehen, ausser daß sie nicht gehen, ansonsten gehen sie oder wie war das gemeint?

    Also Smart-pointer gehen. Gibt es leider noch nicht in der Standardbibliothek.

    Ist auto_ptr etwa kein Smartpointer? Smartpointer heißt nicht "referenzgezählt und tiefe Kopie". auto_ptr können syntakisch korrekt mit einem Container verwendet werden. Deshalb gehen sie. Semantisch ist es aber völliger Schwachsinn, da bei Zuweisung eine Besitzübertragung und keine Kopie stattfinden. Deshalb gehen sie doch nicht, obwohl sie anscheinend gehen. Geht das so?



  • Also wenn die Liste auch die Verwaltung der Objekte übernimmt, sprich ihr einziger Aufbewahrungsort ist, so sollte man vielleicht das in Betracht ziehen. Dann müssten auch die STL Algorithmen und Prädikate auf Anhieb funktionieren und man spart sich die unübersichtliche zweite Dereferenzierung eines Iterators.



  • 7H3 N4C3R schrieb:

    auto_ptr können syntakisch korrekt mit einem Container verwendet werden. Deshalb gehen sie.

    Nope. Standard-konforme auto_ptr können nicht zusammen mit Standard-konformen Containern verwendet werden, da die Signatur des Copy-Ctors dies nicht erlaubt.

    Nun gibt es aber Libraries die die Instanziierung eines Containers mit einem auto_ptr doch erlauben. In diesem Fall trifft dann aber der Teil mit dem "semantischen Schwachsinn" zu. Es sei denn natürlich man hat eine nicht-konforme auto_ptr-Implementation wie z.B. dies des VC 6. Hier ist es sogar semantisch ok. Dafür dann aber "Portabilitätsblödsinn".

    Oder kurz: Never create containers of auto_ptrs (Scott Meyers: Effective STL - Item 8).


Anmelden zum Antworten