Problem mit Klassenhierarchie.



  • Belli schrieb:

    Hier scheint es mir schon mal sinnvoller zu sein, das anders herum zu machen, also Strassen - die ja umfangreicher sind - von zB einer Firma - die ja weniger können muß - abzuleiten und entsprechend zu erweitern.

    Das selbe ging mir im Nachhinein auch durch den Kopf, doch da ich die Klasse street schon fertig hatte wollte ichs nimmer ändern ;P
    Ausserdem hätte die Klasse companies (durch mein oben angegebens prob.) dann noch mehr sinnlose virtuelle methoden rumfliegen als es street jetzt schon hat 😕

    asc schrieb:

    (Es gibt immer noch die bessere Alternative: Komposition).

    hmm, wenn ich mich nicht irre würde das in meinem Fall bedeuten in der Mutterklasse(zb) selbst die Objekte der andren Felder zu halten oder zu referenzieren.

    Find ich für mein Problem unpassend da ichs eigentlich recht angenehm finde eine Klasse Board zu haben welche dass Spielbrett darstellt und alle darauf befindlichen felder hält. (in form des field_ptr_[] s)

    oder hab ich das mit der Komposition falsch verstandn ?



  • pumuckl schrieb:

    Wenn du in der Mutterklasse eine Methode als virtuell deklariert hast, dann wird beim Aufruf über einen pointer (oder eine Referenz) immer die entsprechende methode der am weitesten abgeleiteten Klasse aufgerufen.

    Nene, die Runtime-Umgebung erkennt schon, von welchem Typ das Objekt ist, und ruft die Methode dieses Typs auf, und nicht etwa eine einer weiteren von diesem Typ abgeleiteten Klasse.



  • sust schrieb:

    oder hab ich das mit der Komposition falsch verstandn ?

    // Vererbung
    // Vererbung bedeutet "Ist ein"
    class A : public B {/**/};
    
    // Komposition
    // Komposition bedeutet "Enthält", "ist Teil von"
    class A
    {
        private:
            B b;
        /**/
    };
    

    Das ganze kann man natürlich auch wieder mit Schnittstellen (Im Sinne von "Interface" aus anderen Sprachen) kombinieren. In C++ sind das rein virtuelle Basisklassen.

    cu André



  • sust schrieb:

    Das selbe ging mir im Nachhinein auch durch den Kopf, doch da ich die Klasse street schon fertig hatte wollte ichs nimmer ändern ;P

    Das ist sehr schlecht. Wenn du merkst, dass eine Designentscheidung ein Fehler war, dann solltest du diesen Fehler sofort beheben und nicht aus Faulheit den fehler noch weiter ausbauen. In dem konkreten Beispiel würde ich eine weitere (abstrakte) Klasse in die Hierarchie einführen, die von der "mutteklasse" erbt und alles in sich vereint, was Bahnhöfen, E-Werk und Straßen gemeinsam ist (hypotheken, miete usw.) Am Ende leitest du dann die drei Feldtypen von dieser Klasse ab.

    Belli schrieb:

    pumuckl schrieb:

    [...]

    Nene, die Runtime-Umgebung erkennt schon, von welchem Typ das Objekt ist, und ruft die Methode dieses Typs auf, und nicht etwa eine einer weiteren von diesem Typ abgeleiteten Klasse.

    Natürlich war die am weitesten abgeleitete Klasse in der Vererbungshierarchie des dynamischen typs des Objektes gemeint. 🙄



  • pumuckl schrieb:

    Das ist sehr schlecht. Wenn du merkst, dass eine Designentscheidung ein Fehler war, dann solltest du diesen Fehler sofort beheben und nicht aus Faulheit den fehler noch weiter ausbauen.

    Ich weiß, ich mach das auch gleich noch. Desto länger ich warte umso mehr Arbeit wirds. danke ^^

    pumuckl schrieb:

    In dem konkreten Beispiel würde ich eine weitere (abstrakte) Klasse in die Hierarchie einführen, die von der "mutteklasse" erbt und alles in sich vereint, was Bahnhöfen, E-Werk und Straßen gemeinsam ist (hypotheken, miete usw.) Am Ende leitest du dann die drei Feldtypen von dieser Klasse ab.

    Ich hab selbstschon mit dem gedanken gespielt eine Klasse "BuyableField" oä. zu entwickeln. Am besten ich sag jetzt nicht das ich zu faul war 😶 Ich code da meist lieber an stellen weiter wo "neues" hinzukommt. 😕

    Mein Problem dass meine Mutterklasse (bedingt durch das pointerarray vom typ der mutterklasse, welches alle objekte der felder enthält) alle Methoden der andren Feldern als virtual deklarieren und auch initialisieren muss bleibt allerdings weiterhin bestehn. Mir fällt im moment noch keine Lösung ein 😞



  • sust schrieb:

    Ich hab selbstschon mit dem gedanken gespielt eine Klasse "BuyableField" oä. zu entwickeln. Am besten ich sag jetzt nicht das ich zu faul war

    Das bereust Du später, wenn irgendwelche Kleinigkeiten dann an vielen Stellen geändert werden müssen ...

    sust schrieb:

    Mein Problem dass meine Mutterklasse (bedingt durch das pointerarray vom typ der mutterklasse, welches alle objekte der felder enthält) alle Methoden der andren Feldern als virtual deklarieren und auch initialisieren muss bleibt allerdings weiterhin bestehn. Mir fällt im moment noch keine Lösung ein 😞

    Du mußt die Methoden in der Basisklasse nur deklarieren, aber nicht definieren oder initialisieren.
    virtual void methode(void) = 0;
    zum Beispiel bewirkt, daß Deine Basisklasse abstrakt ist, dh, Du kannst kein Objekt dieser Klasse erstellen. Alle von der Basisklasse abgeleiteten Klassen, die ihrerseits nicht abstrakt sein sollen, müssen diese Methode dann definieren, sonst sind sie auch abstrakt.



  • sust schrieb:

    Ich hab selbstschon mit dem gedanken gespielt eine Klasse "BuyableField" oä. zu entwickeln. Am besten ich sag jetzt nicht das ich zu faul war 😶 Ich code da meist lieber an stellen weiter wo "neues" hinzukommt. 😕

    Da sieht man wieder, auch Programmieren erfordert eine gewisse Disziplin 😉 Klar bringt man lieber neue Funktionalität, aber es lohnt eigentlich immer, aus dem Vorhandenen erstmal ne runde Sache zu machen, bevor man weitere Neureungen einfügt. Sonst wird das rumdoktern an den hässlichen Stellen irgendwann sehr mühselig und die Neuerungen machen auch nciht mehr so viel Spaß.

    Mein Problem dass meine Mutterklasse (bedingt durch das pointerarray vom typ der mutterklasse, welches alle objekte der felder enthält) alle Methoden der andren Feldern als virtual deklarieren und auch initialisieren muss bleibt allerdings weiterhin bestehn. Mir fällt im moment noch keine Lösung ein 😞

    Wenn ich das richtig verstehe meinst du, damit du auf den Elementen des Pointerarrays Funktionen wie kaufen(), hausBauen(), getMietpreis() etc. aufrufen kannst? Die Funktionalität haben ja nun mit gutem Grund nicht alle Felder (weil man Ereignisfelder nicht kaufen kann), deshalb sollte es auch in der Mutterklasse keine derartigen Methoden geben (wie sollte man die schließlich für die Ereignisfelder implementieren?)
    Aber: wenn du ein Feld Kaufen möchtest, musst du natürlich vorher wissen, ob das geht - es wird also für alle Felder (also in der Mutterklasse) eine Methode isBuyable() oder ähnliches geben, die standardmäßig false zurückgibt und bei BuyableField's true. Wenn du aber weißt dass das Field auf dem du grade stehst in wirklichkeit ein BuyableField ist, dann hindert dich nichts an einem Downcast:

    Field* felder[36];
    
    if (felder[i]->isBuyable())
    {
      BuyableField* kaufFeld = dynamic_cast<BuyableField*>(felder[i]); //wir wissen ja dass das geht...
      kaufFeld->kaufen();
    }
    


  • Belli schrieb:

    Du mußt die Methoden in der Basisklasse nur deklarieren, aber nicht definieren oder initialisieren.
    virtual void methode(void) = 0;
    zum Beispiel bewirkt, daß Deine Basisklasse abstrakt ist, dh, Du kannst kein Objekt dieser Klasse erstellen. Alle von der Basisklasse abgeleiteten Klassen, die ihrerseits nicht abstrakt sein sollen, müssen diese Methode dann definieren, sonst sind sie auch abstrakt.

    Ja weiß ich, aber ich kann sie leider nicht rein virtual deklarieren, da ich die methoden sonst in jeder abgeleiteten Klasse einbauen müsste.
    Wo steckt btw. der Sinn dahinter, dass ich eine rein virtuelle Methode in jeder abgeleiteten klasse implementieren muss? 😕 Macht mir das leben schwer..
    Da ich sie also nicht rein virtuell machen kann muss ich sie auch in der in der cpp file definieren. 😞

    pumuckl schrieb:

    Sonst wird das rumdoktern an den hässlichen Stellen irgendwann sehr mühselig und die Neuerungen machen auch nciht mehr so viel Spaß.

    Ich bereus auch grad bitter ^^ Bin gerade am ändern diverser Dinge wofür ich bis jetz zu Faul war... Der Aufwand wär vor einigen Tagen noch ein bruchteil davon gewesen 😕

    pumuckl schrieb:

    Wenn ich das richtig verstehe meinst du, damit du auf den Elementen des Pointerarrays Funktionen wie kaufen(), hausBauen(), getMietpreis() etc. aufrufen kannst? Die Funktionalität haben ja nun mit gutem Grund nicht alle Felder (weil man Ereignisfelder nicht kaufen kann), deshalb sollte es auch in der Mutterklasse keine derartigen Methoden geben (wie sollte man die schließlich für die Ereignisfelder implementieren?)

    Eben, es sind alle Methoden welche irgendein Feld benötigt auch in der Mutterklasse, wo sie allerdings nichts verloren haben. Natürlich werden sie dort nie aufgerufen, weil sich die Objekte durch virtual ja selbst um den richtigen Methodenaufruf kümmern.

    pumuckl schrieb:

    Aber: wenn du ein Feld Kaufen möchtest, musst du natürlich vorher wissen, ob das geht - es wird also für alle Felder (also in der Mutterklasse) eine Methode isBuyable() oder ähnliches geben, die standardmäßig false zurückgibt und bei BuyableField's true. Wenn du aber weißt dass das Field auf dem du grade stehst in wirklichkeit ein BuyableField ist, dann hindert dich nichts an einem Downcast:

    Field* felder[36];
    
    if (felder[i]->isBuyable())
    {
      BuyableField* kaufFeld = dynamic_cast<BuyableField*>(felder[i]); //wir wissen ja dass das geht...
      kaufFeld->kaufen();
    }
    

    Das klingt ganz nach des Rätsels Lösung... Sprich ich kontrolliere vorher um was für eine Art Feld es sich handelt, und caste dann vom Typ Mutterklasse direkt auf das Benötigte Feld (bzw. auf BuyableField). Somit muss ich auf die Felder nichtmehr über den Pointer der vom Typ Mutterklasse ist zugreifen.
    Ist dies "erlaubt"? Casts sind ja meistens nur nötig wenn die Grundstruktur des Programms schonmal falsch is, bzw. es gäbe meist eine schönere Lösung als casten.
    Klingt nach rel. viel Aufwand, aber wenns ein "profi" so machen würde mach ichs gern. 🙂



  • Schönen guten Tag 🙂

    Hab nun eine weiter abstrakte Klasse BuyableField eingeführt welche die gemeinsame Methoden der Kaufbaren Felder vereint.
    Nun bin ich dabei den field_ptr_ der Mutterklasse umzucasten, damit ich in der Mutterklasse nicht sämtliche Methoden deklarieren muss.
    Da ich in meiner Board Klasse jedoch sehr sehr oft mit dem field_ptr_ arbeite, ist dies ein ziemlich hoher aufwand. So einfach es vorher war mit dem field_ptr_ auf alle Felder zuzugreifen, umso umständlicher ist es jetzt jeden zugriff abzuprüfen und auf die richtige Klasse umzucasten.
    Ist dies wirklich eine Sinnvolle und schöne Lösung? Sollte ich sämtliche buyablefields gleich zu beginn im Board umcasten um aufwand zu sparen (wobei mir auch das nicht wirklich "sauber" erscheint) 😕

    danke schonmal, lg



  • [quote="pumuckl"]

    sust schrieb:

    Aber: wenn du ein Feld Kaufen möchtest, musst du natürlich vorher wissen, ob das geht - es wird also für alle Felder (also in der Mutterklasse) eine Methode isBuyable() oder ähnliches geben, die standardmäßig false zurückgibt und bei BuyableField's true. Wenn du aber weißt dass das Field auf dem du grade stehst in wirklichkeit ein BuyableField ist, dann hindert dich nichts an einem Downcast:

    Field* felder[36];
    
    if (felder[i]->isBuyable())
    {
      BuyableField* kaufFeld = dynamic_cast<BuyableField*>(felder[i]); //wir wissen ja dass das geht...
      kaufFeld->kaufen();
    }
    

    Das bedeutet aber doch, daß die Basisklasse genau wissen muß, was es für abgeleitete Klassen gibt ...
    Baut man eine weitere abgeleitete Klasse, zieht das evtl. aufwendige Änderungen in der Basisklasse nach sich.
    Da würde mir im Moment besser gefallen, eine virtuelle Methode namens 'kaufen' in der Basisklasse zu definieren, die einfach 'false' zurückgibt und von abgeleiteten buyable-Klassen entsprechend überschrieben wird.



  • Belli schrieb:

    Da würde mir im Moment besser gefallen, eine virtuelle Methode namens 'kaufen' in der Basisklasse zu definieren, die einfach 'false' zurückgibt und von abgeleiteten buyable-Klassen entsprechend überschrieben wird.

    Das beudeutet aber im Umkehrschluss, dass du in der Basisklasse sämtliche Methoden aller abgeleiteten Klassen kennen musst und damit eben alle abgeleiteten Klassen - das selbe Dilemma also.
    Ergo sollte man weder das eine noch das andere in der Basisklasse deklarieren sondern an den Stellen im Code wo man weiß, welche verschiedenen Feldtypen es gibt, rausfinden mit welchem Feldtyp man es zu tun hat. Im Header von BuyableField könnte z.B. eine (globale) Funktion bool isBuyable(Field*); deklariert werden.

    Wenn allerdings an so vielen Stellen manuell unterschieden werden muss liegt eh meist ein Designfehler vor. Am Besten gibst du uns ein Beispiel wo solch eine Unterscheidung auftaucht und wir schauen mal gemeinsam ob man die nicht automatisch lösen kann.

    Beispiel von mir:

    Field* aktuellesFeld;
    Player player;
    
    void MonopolyZug()
    {
      int wurf = Würfeln();   
      GeheVor(wurf);
      aktuellesFeld->Aktion(player); //Aktion ist virtuelle Methode von Field
    }
    
    EreignisFeld::Aktion(Player& player)
    {
      EreignisKarte karte = ZieheEreignisKarte();
      player.KartenAktion(karte);
    }
    
    GeheGefaengnisFeld::Aktion(Player& player)
    {
      player.AbInDenKnast();
    }
    
    BuyableFiled::Aktion(Player& player)
    {
      if (HatBesitzer())
      {
        player.ZahleMiete(besitzer);
      }
      else
      { player.KaufeFeld(*this); }
    }
    

    In den meisten Fällen kann man aus den Implementationen der virtuellen Methoden die klassenspezifischen Methoden (KaufeFeld usw.) aufrufen und muss daher nicht erst groß rumcasten.



  • Jaaaaaaaaaaaaaaaaaaaa ......

    Das mit der Methode Aktion schwebte mir auch schon im Kopf herum, nur dachte ich mir irgendwie, was, wenn mehrere Aktionen möglich sind.
    Aber nun, wo ich es so ausformuliert sehe, wird es mir eigentlich klarer ...
    Falls verschiedene Aktionen möglich sind, muß ja nun eine Auswahl getroffen bzw. angeboten werden ... und das kann man ja ganz wunderbar in den entsprechenden Klassen passend machen.

    Also ehrlich, jetzt wo ich es so vor mir sehe, begreife ich gar nicht, wieso ich mich vorher so schwer damit getan habe ...



  • Soweit das ich eine virtuelle Methode "Aktion" mache, welche jede FeldKlasse enthält hab ich noch nicht gedacht *schäm*.
    Hört sich eigentlich Prima an, bin nur grad am überlegen ob ich es bei mir auch einsetzen kann.

    Blos, was ist wenn ich mir aus einer Feldklasse mit getter Methoden versch. Daten holen muss, welche ich in meiner Board Klasse ( da diese eigentlich alle Spielabläufe implementiert) benötige. Bis jetzt hab ich die nötigen Methoden direkt von Board aufgerufen und hatte somit den passenden return wert.
    Läuft jetz jeder Feld-Aufruf in Board über "Aktion" so hab ich ein und den selben return Wert egal was ich brauche. : (

    Bestimmt hast du auch dafür eine Lösung, mir fällt keine ein die nicht ungalublich aufwendig wäre *g*

    Bin dann gleich ab ins WE erst Mo wieder da, werd dann noch Codeauszüge posten, würde sich jetz nimmer ausgehn.
    lg



  • sust schrieb:

    Blos, was ist wenn ich mir aus einer Feldklasse mit getter Methoden versch. Daten holen muss, welche ich in meiner Board Klasse ( da diese eigentlich alle Spielabläufe implementiert) benötige.

    Was für Daten muss denn das Board holen? Und vor allem zu welchem Zweck?

    Wenn das Board mit Daten einer speziellen Feldklasse hantiert, macht es etwas feldpsezifisches - und diese feldspezifischen Aktionen kann man eigentlich immer ins jeweilige Feld auslagern.
    Und wenns mal garnicht anders geht hilft häufig sowas:

    Ansatz mit ekligen casts:

    class Board 
    {
      void doEreignis(EreignisFeld& ef);
      void doBuyable(BuyableFiled& bf);
      void doGefaengnis(GeafengisField& gf);
    
      void allgemein()
      {
      if (isereignisfeld)
        doEreignis(dynamic_cast<EreignisFeld&>(*field)); /iih ein cast...
      else if (isbuyble)
        doBuyable(/*... noch ein cast */)
      else //usw.
      }
    };
    

    besser, ohne casts:

    class Board {
      void doEreignis(EreignisFeld& ef);
      void doBuyable(BuyableFiled& bf);
      void doGefaengnis(GeafengisField& gf);
    
      void allgemein()
      {
        field.callspezifisch(*this); //callspezifisch ist virtuell in Field...
      }
    };
    
    EreignisFeld::callspezifisch(Board& theBoard)
    {
      theBoard.doEreignis(*this);
    }
    
    BuyableField::callspezifisch(Board& theBoard)
    {
      theBoard.doBuyableField(*this);
    }
    
    //usw.
    

    Klar, jetzt muss das Board alle Feldtypen kennen, aber das musste es vorher auch schon.



  • Mal ein kurzer Codeausschnitt:

    #include <string>
    #include <vector>
    
    #ifndef BOARD_H_
    #define BOARD_H_
    
    class Piece;
    class Fields;
    class Player;
    
    class Board
    {
      private:
        Piece *piece_;
        Fields *field_ptr_[40];
        int bank_;      // Bank VORERST als integer deklariert.
        Board(Board &);   //No Shallow Copys.
        std::vector<Piece*> pieces_;  // nötig wegen Rückgabe von Vector
    
      public:
        Board(Player *current_player);    /// übergabe von current_player hier für testzwecke!
        virtual ~Board();
        void setPieceToStart(Piece *piece);
        int movePiece(Player *curren_player, int rolled);
        void build(std::string input, Player *current_player);
        void printField(Player *current_player);
        void print();
        void initFields(char ponf[40], char ooff[40], char honf[40]);
        bool checkHouseRule(std::vector<int>& houses, int index);
        bool checkField(Player *current_player, int rolled);
        bool checkInput(int cases);
        int checkBankrupt(Player *current_player);
        void removePossessions();
    };
    
    #endif  //BOARD_H_
    
    //---------------------------------------------------------------------
    #include "BuyableFields.h"
    
    #ifndef STREETS_H_
    #define STREETS_H_
    
    class Streets: public BuyableFields
    {
      private:
        int house_;
        int house_price_;
        int rent_list_[6];
        Colors group_;
        Streets(Streets &);   //No Shallow Copys.
    
      public:
        Streets(std::string field_name, int price, int site, int hse1,
          int hse2, int hse3, int hse4, int hotel,
          int house_price, Colors group, Player *owner = NULL);
        virtual ~Streets();
    
        Colors getGroup();
        void setHouse();
        int getHouse();
        void delHouse();
        int getHousePrice();
        int getRent(int field_count, int rolled);
    
        std::string getFieldType();
    };
    
    #endif  //STREETS_H_
    

    Als kleine veranschaulichung, zwei Headerfiles meiner Klassen. Eine Klasse GameHandler steuert prinzipiell alle Inputs von den Spielern usw. Die Klasse Board (oben angeführt) regelt den weiteren Spielablauf. In den Klassen der Felder ( wie zb streets ) sind lediglich alle Feldrelevanten Daten mit ihren zugehörigen getter und setter Methoden enthalten.
    Imho ist das eigentlich ein sehr schöner Aufbau, die Felder selbst können bebaut, gekauft, vermietet werden. Gesteuert wird dies jedoch vom Board selbst, da die Felder ja über den eigentlich Spielablauf keine Ahnung haben. Nur das Board hat überblick über den gesamten Spielverlauf und kennt alle Regeln etc.
    Wird nun im GameHandler die Methode Build vom Board aufgerufen. So wird Board seinerseids, in der Methode Build Methoden wie getHousePrice(), getHouse() und setHouse() von den Streets aufrufen.

    Lediglich als Beispiel wieso und wie ich in Board eigentlich alles verwalte und warum eine generelle Methode "Aktion()" welche jedes Feld besitzt wohl schwer zu realisieren wird.

    Denkst du das dieser Designansatz komplett daneben ist? Lediglich das Problem mit der Mutterklasse welche alle Methoden kennen muss (ausser durch casts) bleibt dadurch irgendwie bestehen... 😕

    lg



  • Wo bist du pumuckl...? 😞
    Gib mich net auf 😃

    Na spaß, verstehs gut wenns langsam zu "leseintensiv" wird und die Leute hier besseres zu tun haben als meinen Schrott auszubessern. Bedanke mich dennoch mal ganz herzlich bei allen die ihre Zeit für mich geopfert haben. Vll fällt mir ja noch was ein.
    lg



  • Was für Aktionen kann ein Feld denn auslösen?

    Der Spieler kann Geld ausgeben/einnehmen (um ein haus zu bauen, upzugraden, miete zu zahlen, ereigniskarte schnekt ihm geld,...) und/oder er kann besitz bekommen/verlieren (haus, grundstück,..) und/oder es kann seine position auf dem spielfeld ändern.

    damit ist die schnittstelle zwischen feld und board definiert. jedes feld macht alles selber und das board hat keine ahnung was auf einem feld passiert und was das für ein feld ist. ist ihm auch egal, es sagt nur feld.handle() und schon handelt das feld.



  • Hm wies scheint ist mein Beitrag vorhin net angekommen oO

    Ich hatte erstmal zu folgenden Puntke was gesagt:

    1. sollten includes in headern innerhalb der include-guards stehen, nicht davor. Bei größeren projekten können sonst Ringincludes entstehen und dann öffnet der Präprozessor erst A.hpp, dann B.hpp, dann wieder A.hpp, dann B.hpp... irgendwann streckt er alle Viere von sich und aus die Maus 😉
    2. Du übergibst oft Zeiger auf andere Objekte, meist tuns Referenzen auch.
    3. fields würde ich auch zum vector statt zum C-Array machen, schadet nicht.

    Das interface von Board sieht schon recht vollständig aus, mal abgesehn davon dass ich keine Ahnug hab was du mit initFields als public Methode und vor allem mit den ganzen Parametern dort erreichen willst. Die Initialisierung der Felder sollte eigentlich im Konstruktor geschehen.

    Wie Shade schon schreibt, bracuht die Basisklasse für alle Felder wenig mehr als eine virtuelle Methode handle() oder Aktion() mit einem Spieler als Argument. Wenn du einen Spielstein auf dem Board versetzt, nimmst du das Zielfeld und rufst einfach diese Methode auf, mit der Person als Parameter. Das feld selber weiß dann am besten was zu tun ist, z.B. einen Dialog anzeigen "willst du Häuser bauen" oder was auch immer.



  • Ja ihr habt wohl recht.
    hmm, langsam habe ich das Gefühl mein Design scheint etwas unglückglich gewählt.
    Da das Programm zu 90% fertig ist kommt mir die Erkenntnis leider etwas spät. Anstatt der freude am "Erfolg" bleibt nun nur etwas Demotivation. Mal schaun ob der Aufwand das alles zu ändernd lohnt.
    danke, lg



  • pumuckl schrieb:

    1. sollten includes in headern innerhalb der include-guards stehen, nicht davor. Bei größeren projekten können sonst Ringincludes entstehen und dann öffnet der Präprozessor erst A.hpp, dann B.hpp, dann wieder A.hpp, dann B.hpp... irgendwann streckt er alle Viere von sich und aus die Maus 😉

    Danke, hab ich bis jetzt irgendwie immer so gemacht, wobei es total logisch klingt was du sagst.

    pumuckl schrieb:

    1. Du übergibst oft Zeiger auf andere Objekte, meist tuns Referenzen auch.

    Stimmt, arbeite bei der Parameterübergabe zu wenig mit Referenzen. Halte mich da noch zu sehr an die alte Ptrübergabe.

    pumuckl schrieb:

    1. fields würde ich auch zum vector statt zum C-Array machen, schadet nicht.

    *g* zu dem Zeitpunkt wusste ich noch nicht mit containern umzugehen ;P

    pumuckl schrieb:

    Das interface von Board sieht schon recht vollständig aus, mal abgesehn davon dass ich keine Ahnug hab was du mit initFields als public Methode und vor allem mit den ganzen Parametern dort erreichen willst. Die Initialisierung der Felder sollte eigentlich im Konstruktor geschehen.

    initFields ist für die ausgabe des Spielfeldes gedacht. Dabei habe ich für jeden Typ der sich ändern kann auf der Spielfeldausgabe ein chararray angelegt.
    (ponf - peaces on field, ooff - owner of field, honf - houses on field )
    eigentlich würds dann private gehören, stimmt.
    Wär ich zu beginn so klug gewesen und hätte das gesamte Spielfeld intern als string gespeichert wäre mir wohl einiges erspart geblieben. 😞

    pumuckl schrieb:

    Wie Shade schon schreibt, bracuht die Basisklasse für alle Felder wenig mehr als eine virtuelle Methode handle() oder Aktion() mit einem Spieler als Argument. Wenn du einen Spielstein auf dem Board versetzt, nimmst du das Zielfeld und rufst einfach diese Methode auf, mit der Person als Parameter. Das feld selber weiß dann am besten was zu tun ist, z.B. einen Dialog anzeigen "willst du Häuser bauen" oder was auch immer.

    Genau hier scheint mein Design fehlgeschlagen zu sein. Habe die Funktionen für bestimmte Felder in Board implementiert. Das jetzt zu ändern dauert ewig. Sollte das Programm vielleich neu schreiben, blos fehlt mir dazu gerade die Motivation.


Anmelden zum Antworten