Es geht um die Wurst



  • Werner Salomon schrieb:

    so sollte das erstmal gehen

    wurst* make_wurst( std::istream* die_datei ) { // std::istream reicht
        wurst* wurst_neu = new wurst;
        lesen( die_datei, wurst_neu );
        wurst_neu->print();
                // es wird ein Wurst-Objekt korrekt generiert und eingelesen
        return wurst_neu; // mit Wurst-Zeiger raus
    }
    
    int main()
    {
        std::ifstream datei("dateiname");
        wurst* w = make_wurst( &datei );
        w->print();
        delete w; // aufräumen nicht vergessen
        return 0;
    }
    

    Wenn diese noch in einem set< wurst > eingefügt werden sollen, ist es leichter die ganze Wurst zu kopieren 🙂

    wurst make_wurst( std::istream* die_datei ) { // std::istream reicht
        wurst wurst_neu;
        lesen( die_datei, &wurst_neu );
        wurst_neu.print();
        // es wird ein Wurst-Objekt korrekt generiert und eingelesen
        return wurst_neu; // mit der ganzen Wurst raus
    }
    
    int main()
    {
        std::ifstream datei("dateiname");
        std::set< wurst > wuerste;
        wuerste.insert( make_wurst( &datei ) );
        return 0;
    }
    

    dazu benötigst Du aber für wurst einen operator< oder einen eigenen Comperator, um zwei Würste miteinander zu vergleichen. Wenn die Würste in einer Ableitungshierarchie stehen und in dem set auch Objekte anderer klassen untergebracht werden sollen, wird's aufwendiger.

    Gruß
    Werner

    PS.: Klassen, die wurst heißen sind 🕶

    Geht das wirklich ??
    Ich bin mir bei den ganzen Sachen nicht ganz sicher ?!
    Wenn ich in einer Funktion ein neues Objekt erzeuge, wann kann ich es weiter benutzen und wann geht es wieder verloren ?!

    Wollten fuer jedes Lebensmittel ( jede Wurst ist bei uns ( verstaendlicherweise ) ein Lebensmittel ) ein eigenes 'set' generieren, weil es eben sonst zu schwierig wird.
    Wollen nur ueben, keine perfekte Loesung abgeben?

    Eine Frage habe ich doch noch:
    Wieso sollte ich einen neuen Operator< schreiben? Generell ist mir egal, wo ich in meiner Menge einfuege? Vielleicht ein Operator= waere noch sinnvoll, aber mir gerade zu kompliziziert... Oder muss ich das aus irgendwelchen obskuren Gruenden machen ?!

    Schoenen Tach noch ....

    #50



  • Raute50 schrieb:

    Eine Frage habe ich doch noch:
    Wieso sollte ich einen neuen Operator< schreiben? Generell ist mir egal, wo ich in meiner Menge einfuege? Vielleicht ein Operator= waere noch sinnvoll, aber mir gerade zu kompliziziert... Oder muss ich das aus irgendwelchen obskuren Gruenden machen ?!

    Um schnellen Zugriff auf die Elemente im set zu gewährleisten hält set seine Elemente sortiert. Dazu muß es sie aber vergleichen können, daher benötigt es einen funktionierenden operator<.



  • Wenn ich in einer Funktion ein neues Objekt erzeuge, wann kann ich es weiter benutzen und wann geht es wieder verloren ?!

    Alles was du lokalauf dem Stack erzeugst, geht in der funktion(block) auch wieder verloren !
    genau so die uebergabe parameter und der Return-Wert, nach ende des aufrufes ....
    um werte nich zu kopieren, musst eh mit referenzen / pointer arbeiten ...

    int funcX(int * p1 , int * p2)
    {
        int temp1 = 2; // lokal aufm Stack ... 
        p1 = &temp1; // mies, ner nichtlokalen Variable wird ne adresse von nem lokalen Object zugewiesen ... 
        int * ptemp2 = new int; // lokal aufn stack iss nur der Zeiger pTemp an sich, es wird aber speicher fuer ne intvariable aufn freestore erzeugt ... 
        p2 = ptemp2 // p2 wird nu auf die adresse aufn freestore gesetzt, sollte kein problem sein ... 
    } 
    // sobald die funktion zu ende ist, werden deine lokalen variablen ungueltig
    // p1 zeigt nun ins daten Nirvana
    // ptemp2 gibts natuerlich auch nimmer, aber p2 zeigt an die adresse aufn freestore, welche noch ned geloescht ist ... p2 iss noch gueltig
    

    das mit dem dynamisch allokieren in ner funktion und den pointer nach aussen geben gewoehn DIr aber nicht an. Das ist sehr schlechter C++ programmierstil.
    Faustregel: dynamisch speicher allokieren und wieder deallokieren immer syntaktisch beieinander ... (entweder im selben block, in nem object mit extra alloc / dealloc funktion, oder im Konstruktor / destruktor )

    Wollen nur ueben, keine perfekte Loesung abgeben?

    Naja, nix iss perfekt, man sollte sich aber von anfang an gleich mit den problemen vertraut machen, und von anfang an auch am "Stil" arbeiten.

    Viele die ich kenne, haben folgendes Problem:
    Pointer sind wichtig, es ist wichtig das zu verstehen - ok
    Uebern wir mal pointer - ok
    Man pointer sind so klasse generisch, und mit pointer kopiert man auch immer nur 4 Bytes, nie das ganze object, pointer sind klasse ! - falsch ! (rawpointer unter c++ solten die ausnahme sein. wenn dein code aussieht wie sternhimmel bei nacht, solltest noch mal auf C umschulen und c++ sein lassen)

    Lernen ok, aber mit system ....

    Wieso sollte ich einen neuen Operator< schreiben? Generell ist mir egal, wo ich in meiner Menge einfuege? Vielleicht ein Operator= waere noch sinnvoll, aber mir gerade zu kompliziziert... Oder muss ich das aus irgendwelchen obskuren Gruenden machen ?!

    Du arbeitest mit der STL, dazu sollte man die STL kennen. Lerne auch, Informationen ueber die verwendeten Libs zu bekommen !!!

    zum std::set:
    Anforderung: CopyConstructor , Lesser-Comperator (Kleiner-Vergleichsfunktion), per standard wird der < Operator der klasse genommen, kann aber im template ueberschrieben werden ....

    Generell ist mir egal, wo ich in meiner Menge einfuege?

    Lerne die Container der STL sinvoll zu nutzen !!!
    wenn du keine Reihenfolge/sortierung/Zugriff ueber B-Baum brauchst ... warum dann ein Set ???

    Das eigentliche Problem:
    Dein Beispiel klingt eigentlich trivial, beherbergt aber mehr Probleme als du auf den 1 Blick siehst.
    - containerklassen
    - evtl. Operatorueberladung an abgeleiteten klassen
    - Polymorphie, damit bedingt dynamische allokation ...
    - quasi virtuelle Konstruktoren (durch deine serialisierung) -> kann man endlos ausdehnen bis man irgendwo bei Objectfactories anlangt 🙂

    streich aus deinen Anforderung erst mal was raus 😃

    Wie wuerde ich dein problem loesen ....

    - wrapperklasse fuer deinen generischen Wurstzeiger (normal als template, wird aber echt zu kompliziert. ), der alle Informationen / Methoden die deine generischen Wurste (oder lebensmittel) gemeinsam haben inklusive CCtor und lesser operator, so dass das ding in jedes set / map packen kannst ....
    - ne Factory funktion, die die den richtigen Wurstzeigerwrapper(inklusive dynamisches erstelltes Wurst object) gleich erstellt, in abhaengigkeit der Eingangswerte .... eventuell als statische funktion gleich am Wrapper object.
    - und voiala, schon iss nen std:set total easy zu benutzen ...

    Das waer "gutes c++"

    Viel Spass noch beim lernen ! 😃

    Ciao ...



  • RHBaum schrieb:

    von mir selber schrieb:

    Wieso sollte ich einen neuen Operator< schreiben? Generell ist mir egal, wo ich in meiner Menge einfuege? Vielleicht ein Operator= waere noch sinnvoll, aber mir gerade zu kompliziziert... Oder muss ich das aus irgendwelchen obskuren Gruenden machen ?!

    Du arbeitest mit der STL, dazu sollte man die STL kennen. Lerne auch, Informationen ueber die verwendeten Libs zu bekommen !!!

    Ja und wie bekomme ich an die Info's ...??
    Habe bis dato bei www.cplusplus.com und www.c-plusplus.net immer nach Informationen gesucht, jedoch mit unterschiedlichem Erfolg.
    Gibt es eine bessere Quelle ??

    weiter von vorhin ... schrieb:

    zum std::set:
    Anforderung: CopyConstructor , Lesser-Comperator (Kleiner-Vergleichsfunktion), per standard wird der < Operator der klasse genommen, kann aber im template ueberschrieben werden ....

    Habe nachgelesen, das in 'map' automatisch geordnet eingfuegt wird. Habe deswegen den operator < überschrieben, jedoch reicht das nicht.
    Muss ich jetzt alle Relationen überschreiben ?!

    etwas weiter tiefer im Text : schrieb:

    Wie wuerde ich dein problem loesen ....

    - wrapperklasse fuer deinen generischen Wurstzeiger (normal als template, wird aber echt zu kompliziert. ), der alle Informationen / Methoden die deine generischen Wurste (oder lebensmittel) gemeinsam haben inklusive CCtor und lesser operator, so dass das ding in jedes set / map packen kannst ....
    - ne Factory funktion, die die den richtigen Wurstzeigerwrapper(inklusive dynamisches erstelltes Wurst object) gleich erstellt, in abhaengigkeit der Eingangswerte .... eventuell als statische funktion gleich am Wrapper object.
    - und voiala, schon iss nen std:set total easy zu benutzen ...

    Das waer "gutes c++"

    Das glaube ich gerne nur habe ich allein bei ca. 36,94% Deines Textes ( fast gar ) keine Ahnung, was Du von mir möchtest ?! 😕 🙄

    Werde versuchen folgendes mehr zu verinnerlichen :
    - wrapperklasse
    - Generischer Wurstzeiger
    - template
    - CCtor ( sollte das eine Abkürzung für Konstruktor sein )
    - lesser Operator ( oder nur ein Verschreiber für besser, auch wenn bei mir das b und das l auf der Tastatur ziemlich weit voneinander entfernt sind
    - die Bedeutung des Operators ( wie kann ich erreichen, dass etwas sowohl in jedes set als auch in jede map kommen kann ?? )
    - Factory Function
    - Wurstzeigerwrapper ( vielleicht hilft mir die wrapperklasse dabei 😋 )

    nette aufmunternde Worte: schrieb:

    Viel Spass noch beim lernen ! 😃

    Die Hoffnung stirbt zuletzt!

    Trotzdem erst ein Mal ein Danke!

    #50



  • Raute50 schrieb:

    Ja und wie bekomme ich an die Info's ...??
    Habe bis dato bei www.cplusplus.com und www.c-plusplus.net immer nach Informationen gesucht, jedoch mit unterschiedlichem Erfolg.
    Gibt es eine bessere Quelle ??

    Ich benutze das hier als referenz.



  • Ja und wie bekomme ich an die Info's ...??

    STL:
    http://www.sgi.com/tech/stl/

    Naja, aber ehrlich, immer im Inet danach suchen ist laestig umstaendlich etc.
    Wenn wirklich an C++ intressiert bist, wirst frueher oder spaeter Literatur in handfester Form bevorzugen ...

    "Die C++ Standard Biblothek" 3. Auflage mitlerweile, iss ne gute Sache da

    Nen gutes C++ Buch was auf Neueinsteiger eingeht ist auch goldwert, allein um den EInstieg zu finden und paar vernuenftige Beispielprogramm-Ideen zu bekommen(nen Gorssteil der Einsteiger will gleich mit nem 3D SPiel loslegen)

    Habe nachgelesen, das in 'map' automatisch geordnet eingfuegt wird. Habe deswegen den operator < überschrieben, jedoch reicht das nicht.
    Muss ich jetzt alle Relationen überschreiben ?!

    map hat nen key, und Body ...
    Key muss CCtor haben und lesser Operator (oder du ueberschreibst das am Template)
    Body muss nur CCtor haben (wird auch nicht Sortiert)
    CCtor = Copy Constructor

    class C
    {
    public:
        C(); // Standard Ctor
        C(const C & rx); // CCTor mit constanter referenz
        ~C(); //Destruktor, gibts immer nur einen, zum deleten brauch ma keine parameter :p 
        virtual ~C();   // Bei klasse von denen du ableiten(vererben) erlauben willst, solltest du den virtual machen ... 
    }
    

    Warum brauch die map den CCTor ? weil sie in Ihrem Allokierten Speicher eine Kopie deiner klasse anlegt ... auch wichtig zu wissen ! Dazu nimmt sie prinzipiell den CCTor

    nur habe ich allein bei ca. 36,94% Deines Textes ( fast gar ) keine Ahnung, was Du von mir möchtest ?!

    wird schon noch 🙂 iss nich so schlimm, wenn du nich alles gleich verstehst ...

    wrapperklasse - Wrapper - Umhuellung. in C++ eine Klasse, die dir den Zugriff auf was anderes Kapselt, und deinen speziellen beduernissen anpasst. Bei den DesignPatterns(Sammlung von konzeptionellen Musterloesungen) auch manchmal unter Adapter zu finden.
    In deinem Fall eine klasse, die intern einen Rohen zeiger auf ein Wurst-Object haelt, (du erinnerst dich, rohe zeiger allein sind nich so gut in C++) sich um dessen erzeugung und zerstoerung kuemmert, und den Lesser operator sowei CCtor implementiert. Da der lesser operator spezifisch ist bei dir ( was kleiner iss bestimmt dein inhalt), ist das nicht nur nen smartpointer sondern nen Wrapper / Adapter ...

    Generischer Wurstzeiger - zeiger auf ein Wurst Object. Da in deinen Anforderungen die rede von Vererbung ist :

    class Wurst
    {
    public:
        Wurst();
        virtual ~Wurst(); // richtig du willst vererben ,also destrukur immer virtual 
    };
    
    class LeberWurst : public Wurst
    {
        LeberWurst ();
        virtual ~LeberWurst (); 
    }
    
    // irgendwo in den tiefen einer implementation 
    
    LeberWurst * pLeberWurst = new LeberWurst; // erzeugen eines speziellen Leberwurst-Zeigers
    Wurst * pWurst = pLeberWurst; // hier zuweisung deines Speziellen Zeigers an nen generischeren WurstZeiger ...
    

    Das meinte ich mit generischen Wurstzeiger 🙂

    template - Programiertechnik unter C++. Zum schreiben von generischen klassen, ohne vererbung. Template deshalb, weil du keine spezielle klasse in dem moment schreibst sondern nur eine Vorlage (Template) und darin ein oder mehrere platzhalter fuer Datentypen / Werte hasst. erst wenn du die klasse mit nem dem speziellen Datentypen / werten benutzt, ist der compiler in der lage, deinen code zu generieren ...
    Der groesste teil der STL (Standard Template Library) sind templates ....

    CCtor - Copy Construktor - siehe oben

    lesser Operator - < Operator (kleiner (lesser) Operator)
    wird so meist deklariert:

    class C
    {
        // Konstrukor destruktor usw lass ich mal weg
        bool operator < (const C & rx);
    }
    // und schon kann man den verwenden ... 
    C x1; 
    C x2;
    
    if(x1 < x2)
    // usw usf ...
    

    Factory Function - Aus den Design patterns ... Funktionen die nur dafuer da sind, anhand von unterschiedlichen eingangsparametern, unterschiedliche klassen(Leberwurst, Blutwurst, Salami) mit gemeinsamer Basisklasse (Vererbung) zu generieren , dir dann einen Zeiger auf die gemeinsame Basisklasse zurueckgeben (Wurst)

    Wurstzeigerwrapper - ein Wrapper fuern Wurstzeiger 😃

    Hoffe das hilft bisserl weiter, und du bekommst nen Gefuehl, auf was du dich hier einlaesst 😉 😃 🙂

    Tamplates und Designpatters solltest im moment eh nich beachten, das kommt eigentlich ganz ganz spaet ... da braucht man halt schon die anderen grundlagen zu ...

    Ciao ...



  • Sollte der op< nicht besser als binärer friend implementiert werden ?



  • prolog schrieb:

    cd ~/pub
    more beer

    finde ich cool ( auch wenn ich nicht in jedem Ordner ein pub-Verzeichnis habe, deswegen das ~ ) !

    Mache mir als Gag mal so ein Verzeichnis mit so einer Datei.....

    Und nun wieder zu C++ ...

    #50



  • Sollte der op< nicht besser als binärer friend implementiert werden ?

    Jo eigentlich schon ...
    macht aber auch wirklich nur nen Unterschied, wenn du impliziete Konvertierungen zulaesst. Auf der anderen Seite macht ne externe Implementierung nix kapput ... von daher ok, lieber extern als friend.

    Ciao ...



  • Hellas,

    habe diese Version mal versucht zu implementieren:

    Werner Salomon schrieb:

    so sollte das erstmal gehen

    wurst make_wurst( std::istream* die_datei ) { // std::istream reicht
        wurst wurst_neu;
        lesen( die_datei, &wurst_neu );
        wurst_neu.print();
        // es wird ein Wurst-Objekt korrekt generiert und eingelesen
        return wurst_neu; // mit der ganzen Wurst raus
    }
    
    int main()
    {
        std::ifstream datei("dateiname");
        std::set< wurst > wuerste;
        wuerste.insert( *make_wurst( &datei ) ); 
            // Im Original ohne * funktioniert aber nur mit *
        return 0;
    }
    

    dazu benötigst Du aber für wurst einen operator< oder einen eigenen Comperator, um zwei Würste miteinander zu vergleichen. Wenn die Würste in einer Ableitungshierarchie stehen und in dem set auch Objekte anderer klassen untergebracht werden sollen, wird's aufwendiger.

    Gruß
    Werner

    PS.: Klassen, die wurst heißen sind 🕶

    Den Operator< habe ich so geschrieben :

    friend bool operator< ( wurst w,wurst v)
    		{
    		 			 return ( w.qualitaet > v.qualitaet);
    		}
    

    und die abgeänderte Version von make_wurst() sieht so aus

    wurst* make_wurst2( std::ifstream *datei)
    {
     			 wurst* neu = new wurst;
     			 lesen(datei, neu);
     			 neu->print();
     			 return neu;
    }
    

    meine main() sieht so aus :

    int main(int argc, char *argv[])
    	set<wurst> Wuerste;
    	std::ifstream datei("dateiname");
    	char c;
    	datei.get(c);
    	datei.get();
    	datei.get();
    	switch (c) {
    		case 'K' :
    			break;
    		case 'W' :
    			cout <<"es ist eine WURST\n\n";
    			Wuerste.insert(*make_wurst2(&datei));
    			Wuerste.insert(*make_wurst2(&datei));
    			Wuerste.insert(*make_wurst2(&datei));
    
    			cout << "Ich habe nun " << Wuerste.size()
    					 << "Wuerste am Start!";
    			//make_wurst(&datei,w,wurst_pointer);
    			break;
    		default :
    			cout <<" Wieso komme ich in dieses besch...  default rein ?! ";
    	}
        cout <<" \n\n\nFertig!\n\n";
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    In dateiname steht folgendes:

    W::wurst,2.22,3,4,5,6,77,TIER
    W::wurstchen,2.34,5,6,7,8,90,jaja
    W::wuerste,1.23,9,8,7,6,574,nein
    K::CH,2.2,3,4,5,6,7,gauda
    NName,2.99,4,5,
    leb,1,3,4,55,6,777,
    

    Und es tut was es soll ... ( nicht das mich das stört ) !!!

    Nur leider habe ich das immer noch nicht so ganz verstanden ...
    🙄
    🙄
    🙄

    Wenn ich in der lokalen Funktion ein Wurst-Objekt generiere und den Zeiger darauf zurück gebe, wieso klappt das ????

    Hoffe ihr verzweifelt nicht an mir, wie ich an C++!

    Mache dies nicht ganz freiweillig... Ist ein Projekt, welches meinen Namen mit tragen soll... nur sehe ich schwarz bei meinen Erfolgen ( zu denen ich auch 'Hallo Welt' zähle ) ...

    Bis bald vielleicht !!!

    #50



  • Ok, dann schritt fuer schritt 🙂

    mach dir mal paar gedanken wie man so beim design vorgeht:
    Design ist so die wichtigste phase, die implementation dann eigentlich nur noch fleissarbeit (wennd as design gut war 😃 ).

    1. Frage

    W::wurst,2.22,3,4,5,6,77,TIER
    W::wurstchen,2.34,5,6,7,8,90,jaja
    W::wuerste,1.23,9,8,7,6,574,nein
    K::CH,2.2,3,4,5,6,7,gauda
    NName,2.99,4,5,
    leb,1,3,4,55,6,777,

    Die Dateistructur ist vorgegeben, kannst also nicht selbst was drann drehen ?
    wenn ja, wie fest(stabil gegen veraenderungen) ist die ?

    Dein Code in bezug auf den zugriff auf den stream sieht .. argl .. aus 🙂
    muss man 3 mal hinschauen, um zu sehen was da machst.
    Intuitiver (und damit besser wartbar) waere sowas wie :

    std::ifstream datei("dateiname");
    while (!datei.eof())
    {
        Datensatz dat;
        datei >> dat;
        // und hier irgendwas mit dem Datensatz tun ... 
    }
    

    Deswegen frage ich, wie die datei aussieht, und ob du das drehen kannst, bzw. wie sicher die vor veraenderungen ist ....
    Dann kann man die Datensatz klasse modellieren ....

    Weiterer Prinzipieller Weg:

    deine Spaeteren Objecte (leider willst ja unbedingt polymorphie haben 😃 )
    muessen ja alle geminsam zu irgendwas nuetze sein 🙂
    diese Gemeinsamkeiten must herausfinden, und in ner Schnittstelle definieren ....

    sowas wie:

    class ILebensMittel
    {
    protected: 
        ILebensMittel(){};
        virtual ~ILebensMittel(){};
    public:
        float getPreis() const = 0;
        const std::string & getName() const = 0;
        // was weiss ich nich noch alles :-) 
    };
    

    Ok, weiter gehts dann in der naechsten Folge 🙂

    Ciao ..



  • Raute50 schrieb:

    Wenn ich in der lokalen Funktion ein Wurst-Objekt generiere und den Zeiger darauf zurück gebe, wieso klappt das ????

    Denke du sprichst die Funktion make_wurst2 an.
    Warum sollte das nicht funktionieren. Du generierst die wurst ja am heap. Niemand überschreibt deine Wurst. Anders würde es aussehen wenn make_wurst2 so gecodet wäre:

    wurst * make_wurst( std::istream* die_datei ) { 
        wurst wurst_neu;
        lesen( die_datei, &wurst_neu );
        wurst_neu.print();
        return & wurst_neu; 
    }
    

    In diesem Fall liegt wurst_neu am Stack. Sie wird zwar wahrscheinlich dort noch immer sein wenn make_wurst zum Aufrufer zurückkehrt aber die nächste Funktion die aufgerufen wird verwendet den speicher von wurst_neu und wurst_neu wird überschrieben. Du kannst also die wurst nicht mal kopieren ohne sie zu zerstören.
    Kurt



  • RHBaum schrieb:

    Ok, dann schritt fuer schritt 🙂
    1. Frage

    W::wurst,2.22,3,4,5,6,77,TIER
    W::wurstchen,2.34,5,6,7,8,90,jaja
    W::wuerste,1.23,9,8,7,6,574,nein
    K::CH,2.2,3,4,5,6,7,gauda
    NName,2.99,4,5, < hier fehlt eine Zahl, ist mir gerade aufgefallen 🙂 >
    leb,1,3,4,55,6,777,

    Die Dateistructur ist vorgegeben, kannst also nicht selbst was drann drehen ?
    wenn ja, wie fest(stabil gegen veraenderungen) ist die ?

    Die Datenstruktur haben wir uns selber ausgedacht ...
    Vererbungshierarchie: Produkt->Lebensmittel->Wurst, Kaese, ...
    Eigenschaften:
    - Produkt ( char* name,double preis,unsigned int bestand,unsigned int kapazitaet),
    - Lebensmittel ( zusätzlich unsigned int gewicht,int haltbarkeit,unsigned int qualitaet),
    - Wurst ( zusätzlich nur char* tier)
    - Kaese ( adäquate andere 'Zusätze')

    Oben ist NName ein Produkt und leb ein Lebensmittel, die Kommata stehen in der Ausgabe nur, weil wir die einzelnen print() Methoden ausprobiert haben.
    Lieber eine Debug Ausgabe zuviel, als einen Tag Fehlersuche.

    Dein Code in bezug auf den zugriff auf den stream sieht .. argl .. aus 🙂
    muss man 3 mal hinschauen, um zu sehen was da machst.
    Intuitiver (und damit besser wartbar) waere sowas wie :

    std::ifstream datei("dateiname");
    while (!datei.eof())
    {
        Datensatz dat;
        datei >> dat;
        // und hier irgendwas mit dem Datensatz tun ... 
    }
    

    Die main() sieht nur so aus, weil wir am Anfang stehen, also ist der weitere detaillierte Weg noch offen.
    Wir haben uns nur überlegt, wie wir die sets mit den nötigen Objekten füttern...
    In der main() kann man gut sehen, dass wir es an einer Wurst überprüfen wollten, bevor wir weiter in's Detail gehen.

    Deswegen frage ich, wie die datei aussieht, und ob du das drehen kannst, bzw. wie sicher die vor veraenderungen ist ....
    Dann kann man die Datensatz klasse modellieren ....

    Weiterer Prinzipieller Weg:

    deine Spaeteren Objecte (leider willst ja unbedingt polymorphie haben 😃 )
    muessen ja alle geminsam zu irgendwas nuetze sein 🙂
    diese Gemeinsamkeiten must herausfinden, und in ner Schnittstelle definieren ....

    sowas wie:

    class ILebensMittel
    {
    protected: 
        ILebensMittel(){};
        virtual ~ILebensMittel(){};
    public:
        float getPreis() const = 0;
        const std::string & getName() const = 0;
        // was weiss ich nich noch alles :-) 
    };
    

    Ok, weiter gehts dann in der naechsten Folge 🙂

    Ciao ..

    den letzten Teil verstehe ich nicht, bzw. ich sehe nicht ein, was mir das im Moment bringt?!

    P.S.:
    Muss leider gleich zur Arbeit....
    Werde dieses Mal wohl ein wenig zögern, bevor die nächste Frage ( auch wenn sie für euch noch so dumm aussehen mag ) stelle, die mich zum VErzweifeln bringt!

    In diesem Sinne ....

    #50



  • den letzten Teil verstehe ich nicht, bzw. ich sehe nicht ein, was mir das im Moment bringt?!

    Was willst du alles mit den Lebensmitteln machen ???
    Du willst doch vielleicht irgendwelche preise ausgeben, listen drucken etc ...

    Dazu gibt es 2 Wege ...

    1. du kreirst eine klasse die alles kann ...
    Also eine lebensmittel-klasse die z.B nen Typ ausgeben, Name und so ...
    Felder fuer alle möglichen Daten hat, und bei den typen wo man bestimmte daten nicht braucht, setzt man überall platzhalter ein ...

    Vorteil: du brauchst keine Polymorphie

    Nachteil: wenn irgendwo mal nen neuer lebensmitteltyp hinzukommt, aenderst alle funktionen die in irgend einer weisse mit der Lebensmittleklasse ueberhaupt zu tun haben ... vergisst irgendwas -> undefiniertes / unlogisches verhalten ...

    2. du ueberlegst Dir ne schnittstelle, was alle lebensmittel koennen muessen fuer die speziellen aufgaben ....
    Du kannst dir schoene Aufgaben.Objecte(klassen) anlegen, zum drucken, preise berechnen etc, die nur deine Schnittstelle kennen muss.

    Nachteil: Du brauchst Polymorphie, du bracuhst zumindest ne rudimentaere Objectfabrik

    Vorteil: wenn neue Lebensmitteltypen hinzukommen / bzw sich das von verhalten von anderen anedert ... uberschreibst nur an der betroffenen klasse die virtuellen funktionen ... du brauchst die anderen klassen nich mehr anzufassen.

    Bei ganz kleinen projekten, kann man drueber streiten, welcher weg besser ist ... wenn man alles im Blick hat, nie niemals nen anderer den code uebernehmen muss, grosse erweiterungen so gut wie ausgeschlossen sind , dann kann man durchaus mal weg 1 nehmen ...

    Bei richtigen projekten -> weg 2

    An der Stelle entscheidest du ... zwischen super design, aber unendlich aufwand, projekt wird masslos teuer schon vor der ersten version ... und schneller Implementation, schnelle ergebnisse, aber wenn der programmierer wegfaellt, bzw aenderungen ins haus stehen, artet alles aus ... mal schnell "wir bekommen fisch dazu, der hat nen parameter 'Graeten pro kg' " iss dann nich mehr trivial ....

    Aber so wie ich sehe, wuerdest du lieber weg 1 nehmen ? erstmal ...
    dann Fang mal an die lebensmittelklasse zu modellieren ...
    Ohne polymorphie "erstmal" ne klasse nur fuer "wurst" zu modellieren, wird nicht funktionieren .... weil spaeter aenderst du dann wirklich alles wieder, wenn du was erweiterst ...

    wobei mir wirklich der hintergrund fehlt, was genau du alles machen willst ...
    getrennte Listen fuer Wurst, Kaese Fisch ... etc machen vielleicht sinn, wenn du nicht viele operationen hasst, die auf alle typen angewand werden muessen ...

    Ciao ...



  • RHBaum schrieb:

    Aber so wie ich sehe, wuerdest du lieber weg 1 nehmen ? erstmal ...
    dann Fang mal an die lebensmittelklasse zu modellieren ...
    Ohne polymorphie "erstmal" ne klasse nur fuer "wurst" zu modellieren, wird nicht funktionieren .... weil spaeter aenderst du dann wirklich alles wieder, wenn du was erweiterst ...

    Falls ich das richtig verstanden habe, haben wir Weg 2 gewählt.
    Wir haben ( nur in Ansätzen ) versucht so viel wie möglich so früh wie möglich zu implementieren. Sprich gibName(), gibPreis(), ... an der Stelle zu implementieren, wo die Eigenschaften auftreteten ( in diesem Falle schon in Produkt ). Und jedes Mal wenn geerbt wird, wird nur das neu implementiert, was auch neu dazugekommen ist, z.B. bei Lebensmittel Haltbarkeit ( denn nicht automatisch jedes Produkt hat ein MindesHaltbarkeitsDatum ).
    Also ich denke, wir haben den Weg 2 eingeschlagen....

    Dieses soll ja auch nur eine Gewöhnung sein, damit wir ( wenn die wirkliche Arbeit kommt ) auch nach 'gutem Stil' programmieren ( so fern es uns möglich ist ).

    der Herr RHBaum mal wieder schrieb:

    wobei mir wirklich der hintergrund fehlt, was genau du alles machen willst ...
    getrennte Listen fuer Wurst, Kaese Fisch ... etc machen vielleicht sinn, wenn du nicht viele operationen hasst, die auf alle typen angewand werden muessen ...

    Na gut dann kommt hier Der Hintergrund:
    Wir wollten uns im Detail mit Vererbung ( und alles was dazu gehört, sprich Überladen von Funktionen, ... ) beschäftigen und haben uns deswegen Produkte.h überlegt, von denen wir erben, nämlich Lebensmittel und Getränke als erstes. Davon wollten wir weiter erben, unter anderem kommt hier die Wurst.
    So weit ging alles gut.

    Dann haben wir versucht uns mit Schreiben in und Lesen aus einer Datei zu beschäftigen, und wollten uns eine sinnvolle Aufgabe dazu ausdenken.
    An dieser Stelle kommt der Verwalter in das Spiel, der alle Bestände kontrollieren soll.
    Er soll ( in unserem Beispiel ) aus einer korrekt gespeicherten Datei lesen und so die Regale füllen, was bedeutet, dass er für jede Ware ( Wurst, Käse, ... ) einen set erzeugt und diesen befüllt.

    Also wie im Film: Alles frei erfunden!

    Hoffe bei euch sind jetzt ein paar Unklarheiten verschwunden!?

    P.S.:
    Wenn ihr mir sagt wie, poste ich euch mal die gesammelten Werke, die wir haben ..

    #50


Anmelden zum Antworten