Kompilierzeitprobleme mit modularer Programmierung



  • camper schrieb:

    Das hättest du anders zitieren sollen. So macht es den Eindruck, als wollte Nexus sich als Dichter betätigen.

    Dass man es als Gedicht erkennen könnte, war eigentlich nie meine Absicht - aber meine stichwortartige Beschreibung kommt da halt schon nahe 😉

    Badestrand schrieb:

    drakon schrieb:

    Fände ich sauberer, als da mit Singletons zu arbeiten.

    Ich finde das hört sich schon ziemlich nach Singleton an. Überall Zeiger rumzureichen finde ich da viel viel ekliger.

    Nexus schrieb:

    Grundsätzlich wäre fast alles mit Vorwärtsdeklarationen und Zeigern als Member zu lösen.

    Mach das bloß nicht. Ist imo unsinning, genauso mit Smartpointern. Ich würde nie "reine" Membervariablen gegen Kompilierzeit eintauschen.

    Puh, endlich mal jemand, der das Ganze so sieht wie ich 😉
    Was das Zeiger-Rumreichen betrifft, wäre das wirklich total eklig, da dann jede Funktion, die entweder Eingaben oder Bildschirmausgaben handhabt, noch einen zusätzlichen Parameter hätte (oder jede Klasse noch einen zusätzlichen Zeiger). Zum Teil wären auch noch ganz andere Funktionen betroffen, weil z.B. auch eine Instanz einer Zufallsgeneratorklasse in Master steht. Das würde sich hinten und vorne nicht lohnen.

    Naja, ich hab mich einfach gewundert; wenn man beginnt, modular zu programmieren, sind plötzlich wieder Unmengen "Hilfsmittel" erforderlich, dass man es nur schafft, nicht schlechtere Voraussetzungen als bei nicht-modularer Programmierung zu haben... Wahrscheinlich nehm ich doch lieber die längere Kompilierzeit in Kauf...

    Ach ja, noch was: Gibt es so was wie meine Masterklasse häufig in der Praxis? Ich finde es sehr praktisch, da ich in main() gerade mal zwei Anweisungen habe. Das Unschöne ist vielleicht, dass Master nur statische Member und Methoden hat, aber wie gesagt mach ich da vielleicht noch ein Singleton draus.



  • Nexus schrieb:

    Naja, ich hab mich einfach gewundert; wenn man beginnt, modular zu programmieren, sind plötzlich wieder Unmengen "Hilfsmittel" erforderlich, dass man es nur schafft, nicht schlechtere Voraussetzungen als bei nicht-modularer Programmierung zu haben... Wahrscheinlich nehm ich doch lieber die längere Kompilierzeit in Kauf...

    Was du aber bedenken solltest: In der Anfangsphase wo man viele Interfaces aendert und oft nur mit mockups herumwirft und jedweder code total instabil (aus aenderungssicht - nicht bug-sicht) ist, sind mehrere uebersetzungseinheiten natuerlich doof, da so das linken laenger dauert.

    sobald du aber einen stand erreicht hast wo ein teil des codes interface-stabil ist, sinken die compiletimes rapide. denk einfach nur daran, dass du ja einen grossteil der dateien nachdem sie einmal fertig sind kaum noch anfasst. am anfang, wo du aber jede datei dauernd aenderst - ists natuerlich etwas stoerend.

    und auch aktuell, also trotz grossem recompile kann ich mir nicht vorstellen dass die compilezeiten soviel groesser sind. denn alles was mehr gemacht wird sind mehrmals header parsen -> und das laesst sich mit precompiled headers sogar umgehen.

    wenn du compilezeiten extrem senken willst, dann schau dir das pimpl-idiom an. ich bin kein grosser fan davon, wenn es aber um reduzierung von abhaengigkeiten geht ist es einfach super.

    20 sekunden recompile deutet auf entweder einen sehr langsamen rechner hin oder auf viel code. und bei viel code: warum aenderst du die zentralen stellen dauernd?



  • und bei viel code: warum aenderst du die zentralen stellen dauernd?

    :p

    Weisst du, was mir da manchmal passiert?
    Ich schaue mal ein wenig im Core, ob alles stimmt usw. Und aus reiner Gewohnheit mache ich da auch aus dem Reflex raus ctrl+s.. Und ich bemerke meinen Fehler auch sogleich beim drücken. *grml*
    Lösung: ctrl+F7 und mal was trinken gehen. 😃



  • drakon schrieb:

    und bei viel code: warum aenderst du die zentralen stellen dauernd?

    :p

    Weisst du, was mir da manchmal passiert?
    Ich schaue mal ein wenig im Core, ob alles stimmt usw. Und aus reiner Gewohnheit mache ich da auch aus dem Reflex raus ctrl+s.. Und ich bemerke meinen Fehler auch sogleich beim drücken. *grml*
    Lösung: ctrl+F7 und mal was trinken gehen. 😃

    dann ist dein editor komisch... wenn es keine aenderung gibt, sollte er die datei nicht modifizieren, auch bei einem ctrl+s nicht...

    aber klar, sowas passiert mal dass man aus versehen eine zentrale datei unnoetigerweise "aendert" - aber das ist hoffentlich ausnahme und nicht regel 😉



  • dann ist dein editor komisch... wenn es keine aenderung gibt, sollte er die datei nicht modifizieren, auch bei einem ctrl+s nicht...

    aber klar, sowas passiert mal dass man aus versehen eine zentrale datei unnoetigerweise "aendert" - aber das ist hoffentlich ausnahme und nicht regel

    Meist ist hald so, dass ich dennoch eine Taste drücke und dann speichere.. 🙂

    Ja, ich schaue schon, dass das nicht all zu oft passiert. Es ist in der Tat recht mühsam nacher alles neu compilen zu müssen.. 🙂


  • Administrator

    Nexus schrieb:

    Nun ist es so, dass Kollisionsabfragen in Object passieren, d.h. da werden schon mal die Klassen Tile und Game (aktuelle Oberfläche) benötigt.

    Also wenn schon würde ich Tile auch von Object ableiten und somit Tile auch als Kollisionobjekt ansehen. In der Klasse Object gibt es eine Methode, welche ein anderes Object annimmt und dann die Kollisionsabfrage ausführt.

    Nexus schrieb:

    Bei den Klassen Player , Enemy und Weapon muss ich wahrscheinlich eine Dreiecksabhängigkeit einrichten, weil sich diese Klassen jeweils gegenseitig beeinträchtigen können.

    Wird wohl nicht nötig sein, zumindest nicht in den Headern. Da kannst du überall Forward Declaration anwenden.
    Du wirst ja wohl kaum ein Player, Enemy oder Weapon kopieren wollen. Von überall her, wo du eine Instanz auf den Player, Enemy oder Weapon übergeben tust, soll es ja auch die gleiche sein. Also wirst du in erster Linie Zeiger herumreichen. Vor allem auch, weil du die Spieler, Gegner und Waffen auf dem Heap erstellen wirst. Und es sicher Möglichkeiten gibt, dass es keine Gegner, keine Waffen oder keine Spieler hat, also Nullzeiger.

    Nexus schrieb:

    Game selber benötigt natürlich alle Klassen, die Typen der Member sind.

    Kommt drauf an, wie zentral du Game gestaltest. Vergiss nicht, dass man in Module auslagern sollte. Man kann auch Funktionsweisen oder Handlungen in Objekte packen, auch Beschreibungen sind möglich. Oder anders ausgedrückt:
    Nicht nur Nomen sind Objekte, sondern auch Adjektive, Verben, Adverben, Pronomen und was es sonst noch alles gibt 😉

    Nexus schrieb:

    Was ein Problem darstellt, ist die Tatsache, dass z.B. Player indirekt über die Basisklasse Object auf Game Zugriff haben muss, um z.B. Kollisionsabfragen mit den Tiles zu handhaben.

    Das leuchtet mir überhaupt nicht ein. Wieso kann der Player nicht direkt mit den Tiles interagieren? Game sollte höchstens den Player verschieben oder sowas ähnliches.

    Nexus schrieb:

    Was wiederum nicht geht, weil im Konstruktor von Game ja auch Player konstruiert wird, und der this -Zeiger von Game zu diesem Zeitpunkt noch auf die Basisklasse Surface verweist... 🙄

    Ah, da haben wir wieder so ein Problem. Du erstellst den Player als Eigenschaft von Game. Aber ist er das wirklich? Ich finde das irgendwie nicht. Einem Game Objekt sollte ein Player Objekt zugewiesen sein, vielleicht auch mehrere, aber es sollte den Player sicher nicht besitzen.
    Ein Spieler sollte meiner Meinung nach anderswo erstellt und dem Spiel dann übergeben werden.

    Nexus schrieb:

    Grundsätzlich wäre fast alles mit Vorwärtsdeklarationen und Zeigern als Member zu lösen. Was ich jedoch unnötig finde, weil auf ich eigene Speicherverwaltung lieber verzichte, wo sichs vermeiden lässt (und wie gesagt auf The Big Three).

    Auf "The Big Three" verzichtest du, in dem du Zeiger verwendest. Aber wenn du möglichst Zeiger meiden willst, weil du Angst vor der eigenen Speicherverwaltung hast, dann solltest du vielleicht eine andere Sprache wählen? C# oder Java? Bei C++ sind ja gerade solche Dinge ganz entscheidend und vieles wird darüber aufgebaut. Man verzichtet einfach auf einen ganz entscheidenden Teil der Sprache, wenn man keine eigene Speicherverwaltung einsetzt. Shared Pointer und ähnliches sollten nur Hilfskonstrukte für gewisse Situationen sein, aber nicht für alles.

    Ich hoffe ich konnte dir etwas helfen. Vor allem überwinde deine Angst vor der Speicherverwaltung!

    Eine "Master-Option"-Klasse, mache ich höchst selten. Das hat den einfach Grund, dass wenn man die Sache genügend aufsplittet in Objekte und Module, es irgendwann keine Option geben wird, welche für alle oder mehr als die Hälfte gilt. Man sollte zudem, meiner Meinung nach, nicht in solchen Dimensionen denken. Wenn eine Option verändert wird, dann betrifft das direkt entsprechende Objekte und dort sollten die Eigenschaften entsprechend gesetzt werden. Man sollte nicht Optionen zusammenschaufeln und in eine gemeinsame Klasse verfrachten. Ausser das sie Optionen sind, haben diese nämlich nichts gemeinsam!

    Grüssli



  • Vielen Dank für die hilfreichen Antworten! Es ist wirklich nett, wie ihr euch Zeit nehmt!

    Shade Of Mine schrieb:

    Was du aber bedenken solltest: In der Anfangsphase [...] sind mehrere uebersetzungseinheiten natuerlich doof, da so das linken laenger dauert.
    sobald du aber einen stand erreicht hast wo ein teil des codes interface-stabil ist, sinken die compiletimes rapide.

    Hmm, das hat in der Tat was, daran hab ich eigentlich gar nicht gedacht 😉

    Shade Of Mine schrieb:

    20 sekunden recompile deutet auf entweder einen sehr langsamen rechner hin oder auf viel code. und bei viel code: warum aenderst du die zentralen stellen dauernd?

    Nein, ich denke nicht, dass der Rechner zu langsam ist. Eher die zweite Möglichkeit. Und wie gesagt lassen sich häufige Änderungen nicht immer umgehen, weil man plötzlich Details bemerkt oder neue Features hinzufügen will, die man vorher noch nicht eingeplant hat. Aber es stimmt schon, ich sollte mich vielleicht ein bisschen einschränken mit zentralen Änderungen.

    drakon schrieb:

    Lösung: ctrl+F7 und mal was trinken gehen. 😃

    Hast du demnach auch das Problem mit langen Kompilierzeiten? Oder sind deine Projekte einfach so riesig? 🙂

    Dravere schrieb:

    Also wenn schon würde ich Tile auch von Object ableiten und somit Tile auch als Kollisionobjekt ansehen. In der Klasse Object gibt es eine Methode, welche ein anderes Object annimmt und dann die Kollisionsabfrage ausführt.

    Nein, dann würde es von der Logik her keinen Sinn mehr machen. Ein Tile ist ja ein fester Bestandteil der Welt, d.h. es kann nur rasterförmig ausgerichtet sein (eben in einer Tilemap) und bewegt sich nicht. Objekte wie der Spieler oder abgefeuerte Waffen hingegen sind mobil und reagieren auf Kollision mit der Welt (also den Tiles).

    Dravere schrieb:

    Nexus schrieb:

    Bei den Klassen Player , Enemy und Weapon muss ich wahrscheinlich eine Dreiecksabhängigkeit einrichten, weil sich diese Klassen jeweils gegenseitig beeinträchtigen können.

    Wird wohl nicht nötig sein, zumindest nicht in den Headern. Da kannst du überall Forward Declaration anwenden.
    Du wirst ja wohl kaum ein Player, Enemy oder Weapon kopieren wollen. Von überall her, wo du eine Instanz auf den Player, Enemy oder Weapon übergeben tust, soll es ja auch die gleiche sein. Also wirst du in erster Linie Zeiger herumreichen. Vor allem auch, weil du die Spieler, Gegner und Waffen auf dem Heap erstellen wirst. Und es sicher Möglichkeiten gibt, dass es keine Gegner, keine Waffen oder keine Spieler hat, also Nullzeiger.

    Ja, also momentan verwalte ich diese Klassen in STL-Containern innerhalb von Game (die eben leer sind falls kein entsprechendes Objekt existiert). Falls es etwas rumzureichen gibt, benutze ich eher Referenzen. Aber das muss ich eh noch ausbauen, jetzt wird z.B. auf die Tiles statt einfacher Übergabe relativ kompliziert zugegriffen - dynamic_cast<Game*>(Master::MySurface)->Tiles (natürlich noch abgekürzt) 😉

    Dravere schrieb:

    Nexus schrieb:

    Was ein Problem darstellt, ist die Tatsache, dass z.B. Player indirekt über die Basisklasse Object auf Game Zugriff haben muss, um z.B. Kollisionsabfragen mit den Tiles zu handhaben.

    Das leuchtet mir überhaupt nicht ein. Wieso kann der Player nicht direkt mit den Tiles interagieren? Game sollte höchstens den Player verschieben oder sowas ähnliches.

    Wie ich schon weiter oben angedeutet habe, hab ich das momentan noch relativ kompliziert (eher global) gelöst. Aber wenn der Spieler direkt mit den Tiles interagieren sollte, müsste ja bei dessen Erstellung im Konstruktor eine Referenz auf die Tiles übergeben werden, und auf Gegner genauso. Gegner wiederum hätten Referenzen auf Spieler und Tiles, was zu Konflikten führt, wenn eines der Objekte noch nicht konstruiert wurde und eine Referenz darauf übergeben wird.

    Dravere schrieb:

    Nexus schrieb:

    Game selber benötigt natürlich alle Klassen, die Typen der Member sind.

    Kommt drauf an, wie zentral du Game gestaltest.

    Dravere schrieb:

    Nexus schrieb:

    Was wiederum nicht geht, weil im Konstruktor von Game ja auch Player konstruiert wird, und der this -Zeiger von Game zu diesem Zeitpunkt noch auf die Basisklasse Surface verweist... 🙄

    Ah, da haben wir wieder so ein Problem. Du erstellst den Player als Eigenschaft von Game. Aber ist er das wirklich? Ich finde das irgendwie nicht. Einem Game Objekt sollte ein Player Objekt zugewiesen sein, vielleicht auch mehrere, aber es sollte den Player sicher nicht besitzen.
    Ein Spieler sollte meiner Meinung nach anderswo erstellt und dem Spiel dann übergeben werden.

    Daran hab ich auch relativ lange überlegt. Ich hab auch eine Klasse Map in Betracht gezogen (für ein Level/eine Karte). Schlussendlich hab ich mich für Game entschieden, weil das so schön zu der Polymorphie mit den Surface s (verschiedene Menüoberflächen) passt (Bei mir ist es so, dass es verschiedene gleichwertige Oberflächen gibt (Hauptmenü, Info, Hilfe, Editor, Game)). Zudem ist es auch logisch sinnvoll, wenn Spieler, Gegner, Tiles gerade erstellt werden, wenn man das Spiel startet (also eine Instanz von Game erstellt). Von mir aus gesehen macht es keinen Sinn, Spieler etc. separat zu erstellen und an Game zu übergeben, weil sie ja unmittelbar daran gebunden sind (welchen Sinn hat ein Spieler ohne Spiel?) 😉

    Dravere schrieb:

    Auf "The Big Three" verzichtest du, in dem du Zeiger verwendest.

    Ich meinte, ich müsse Copy-Ctor, Dtor und Op= selber implementieren, wenn ich Zeiger als Member habe - was ich bei Stackvariablen nicht muss.

    Dravere schrieb:

    Aber wenn du möglichst Zeiger meiden willst, weil du Angst vor der eigenen Speicherverwaltung hast, dann solltest du vielleicht eine andere Sprache wählen? C# oder Java? Bei C++ sind ja gerade solche Dinge ganz entscheidend und vieles wird darüber aufgebaut. Man verzichtet einfach auf einen ganz entscheidenden Teil der Sprache, wenn man keine eigene Speicherverwaltung einsetzt. Shared Pointer und ähnliches sollten nur Hilfskonstrukte für gewisse Situationen sein, aber nicht für alles.

    Vielleicht hab ich einen falschen Eindruck erweckt, es ist ja nicht so, dass ich ängstlich vor Zeigern und eigener Speicherverwaltung zurückschrecke - ich hab immer noch genügend Orte, wo ich mit new und delete arbeite 😉
    Ich meinte vielmehr, dass eigene Speicherverwaltung halt viele Fehlerrisiken birgt und man viel stärker aufpassen muss. Ich sehe deshalb automatische Speicherverwaltung als "Geschenk" an, das auch eingesetzt werden sollte, wenn es geht (im Übrigen ist es auch noch schneller). Wie Badestrand in seinem Post gesagt hat, würde ich Stackvariablen gegen "praktische" Vorwärtsdeklarationen lieber nicht eintauschen.

    Dravere schrieb:

    Eine "Master-Option"-Klasse, mache ich höchst selten. Das hat den einfach Grund, dass wenn man die Sache genügend aufsplittet in Objekte und Module, es irgendwann keine Option geben wird, welche für alle oder mehr als die Hälfte gilt. Man sollte zudem, meiner Meinung nach, nicht in solchen Dimensionen denken. Wenn eine Option verändert wird, dann betrifft das direkt entsprechende Objekte und dort sollten die Eigenschaften entsprechend gesetzt werden. Man sollte nicht Optionen zusammenschaufeln und in eine gemeinsame Klasse verfrachten. Ausser das sie Optionen sind, haben diese nämlich nichts gemeinsam!

    Hm... Was meinst du genau mit "Optionen"? Ich hab das Gefühl, wir stellen uns unter einer Masterklasse nicht ganz das Gleiche vor.
    Bei mir ist es so, dass nur die ganz zentralen Dinge dort geregelt werden. Der Master ist bezeichnenderweise (sorry, wusste keinen besseren Namen als "Master" :)) die oberste Direktive, die alles regelt. Er überwacht den Verlauf des Programms und gibt den einzelnen Oberflächen (abstrakte Basisklasse Surface ) die Kontrolle, wenn eine entsprechende Eingabe getätigt wurde. Abgesehen von der Kontrollfunktion besitzt er noch einige für Grafikroutinen benötigte Variablen (z.B. das Fenster, oder Event für Eingaben, Schriftarten), dient also auch als Ersatz für globale Variablen.

    Aber ganz dezentral kannst du das Programm ja auch nicht steuern (ich nehme nicht an, dass du sehr vieles in der main() -Funktion stehen hast), oder? Ich hab bei mir gerade mal zwei Funktionen in main() , nämlich eine für die Initialisierung und eine für den ständigen Verlauf.

    So, wieder viel geschrieben 🙂
    Ich hoffe, ihr könnt meine Sichtweise und mein Design einigermassen nachvollziehen - bei irgendwelchen Unklarheiten sofort fragen 😉


  • Administrator

    Nexus schrieb:

    Nein, dann würde es von der Logik her keinen Sinn mehr machen. Ein Tile ist ja ein fester Bestandteil der Welt, d.h. es kann nur rasterförmig ausgerichtet sein (eben in einer Tilemap) und bewegt sich nicht. Objekte wie der Spieler oder abgefeuerte Waffen hingegen sind mobil und reagieren auf Kollision mit der Welt (also den Tiles).

    Das bedeutet für mich eigentlich nur, dass du noch nicht genügend aufgesplittet hast. Dann gibt es eben Kollisionsobjekte und bewegliche Objekte. Ein Player wäre demnach beides, ein Tile nur ein Kollisionsobjekt. Durch die Auftrennung passiert dann auch der Logikfehler nicht mehr.

    Nexus schrieb:

    Ja, also momentan verwalte ich diese Klassen in STL-Containern innerhalb von Game (die eben leer sind falls kein entsprechendes Objekt existiert). Falls es etwas rumzureichen gibt, benutze ich eher Referenzen. Aber das muss ich eh noch ausbauen, jetzt wird z.B. auf die Tiles statt einfacher Übergabe relativ kompliziert zugegriffen - dynamic_cast<Game*>(Master::MySurface)->Tiles (natürlich noch abgekürzt) 😉

    Das ist nicht nur kompliziert, sondern sogar langsam! Ein dyamic_cast ist teuer, erst recht, wenn er immer wieder ausgeführt wird. Zudem zeigt ein dynamic_cast, wie so oft, darauf hin, dass ein Designfehler vorliegt. Es sollte ohne gehen!
    Ein Spieler ist nicht da, um sich zu bewegen, Regeln sind dafür da. Und das Spiel, welches die Tiles beinhaltet und auch den Spieler hat, sollte mit den Regeln den Spieler verschieben. Es kann also alles intern gelöst werden.

    Nexus schrieb:

    Wie ich schon weiter oben angedeutet habe, hab ich das momentan noch relativ kompliziert (eher global) gelöst.

    Ich würde eher sagen, sehr vereinfacht und global gemacht, anstatt genügend differenziert 🙂

    Nexus schrieb:

    Aber wenn der Spieler direkt mit den Tiles interagieren sollte, müsste ja bei dessen Erstellung im Konstruktor eine Referenz auf die Tiles übergeben werden, und auf Gegner genauso.

    Nein. Ich hätte da eher an eine Location gedacht. Also sowas wie:

    class Player
    {
      // ...
    private:
      Tile* m_location;
    
      // ...
    public:
      void set_location(Tile* location) { m_location = location; };
      Tile* get_location() const { return m_location; };
    };
    

    Wobei man das sicher ausbauen könnte. Vielleicht in das bewegliche Objekt nehmen. Zudem dann überprüfen, ob es eine Kollision gibt oder was auch immer, bzw. ob der Player dort stehen kann. Wenn nicht, muss das Spiel mit den Regeln richtig reagieren und den Spieler anders verschieben. Die Regeln können ja auch als Klassen eingebaut werden. Dann wird einem Regelobjekt der Spieler übergeben und gesagt, er müsse zum Punkt x,y,z gehen. Die Regel probiert das auszuführen und wenn es nicht geht, übergibt sie die Sache anderen Regeln usw.
    Hier werden dann auch nur Zeiger durchgereicht oder Referenzen.

    Nexus schrieb:

    Gegner wiederum hätten Referenzen auf Spieler und Tiles, was zu Konflikten führt, wenn eines der Objekte noch nicht konstruiert wurde und eine Referenz darauf übergeben wird.

    Wieso hat der Gegner Referenzen auf Spieler? Und wieso überhaupt Referenzen? Wieso nicht Pointer und dann die Übergabe eines Nullpointers erlauben? Ein Spieler könnte keine Waffe haben, ein Spieler oder Gegner kann nirgends stehen.

    Es muss nicht nur das Sinn machen, was der Spieler zu sehen bekommt. Die Funktionsweise eines Spieles sollte mehr können 😉

    Wieso willst du im übrigen alles mit Referenzen lösen? Referenzen kann man nur ein einziges Mal initialisieren, danach kannst du nie mehr ein anderes Objekt zuweisen. Wenn du deinen Klassen immer nur Referenzen übergibst als Member, dann bindest du sie viel zu stark an die entsprechenden Objekte. Das ist meistens gar nicht nötig. Zudem dürfte es Probleme beim "normalen" Kopieren geben.

    Nexus schrieb:

    Daran hab ich auch relativ lange überlegt. Ich hab auch eine Klasse Map in Betracht gezogen (für ein Level/eine Karte). Schlussendlich hab ich mich für Game entschieden, weil das so schön zu der Polymorphie mit den Surface s (verschiedene Menüoberflächen) passt (Bei mir ist es so, dass es verschiedene gleichwertige Oberflächen gibt (Hauptmenü, Info, Hilfe, Editor, Game)). Zudem ist es auch logisch sinnvoll, wenn Spieler, Gegner, Tiles gerade erstellt werden, wenn man das Spiel startet (also eine Instanz von Game erstellt). Von mir aus gesehen macht es keinen Sinn, Spieler etc. separat zu erstellen und an Game zu übergeben, weil sie ja unmittelbar daran gebunden sind (welchen Sinn hat ein Spieler ohne Spiel?) 😉

    Das der Spieler gerade im Warteraum ist? Bei den Optionen? In den Highscores? Jedenfalls nicht im Spiel.
    Zudem sollte man viel eher anschauen, was für Vorteile bringt einem eine entsprechende Kapselung. Sollte wirklich das Spiel den Spieler erstellen? Ich würde eher sagen, das Spiel soll mit dem Spieler interagieren. Erstellen tut sich der Spieler wahrscheinlich selbst, zum Beispiel über ein Profil oder ähnliches. Dann kann er den Namen selber festlegen und die Farbe seiner Spielfigur, oder sowas in der Art 😉

    Nexus schrieb:

    Ich meinte, ich müsse Copy-Ctor, Dtor und Op= selber implementieren, wenn ich Zeiger als Member habe - was ich bei Stackvariablen nicht muss.

    Also hier liegen irgendwie mehrere Missverständnisse vor:
    1. Eine Deep-Copy ist nicht immer nötig. Manchmal will man wirklich nur den Zeiger kopieren und nicht das, worauf der Zeiger zeigt. Siehe es am Beispiel von Player oben. Die Location sollte dort als Zeiger kopiert werden, also eine "flache" Kopie. Man möchte ja auf das gleiche Tile verweisen.
    2. Wenn du Zeiger verwendest, dann musst du ja nicht mehr kopieren! Wenn du dem Spiel ein Zeiger auf einen Spieler übergibst, dann soll der Zeiger gespeichert werden und nur der Zeiger weitergegeben werden (oder allenfalls eine Referenz). Der Spieler wird gar nie kopiert, wodurch er keiner der grossen Drei benötigt.
    3. Stackvariablen? Bei Stackvariablen brauchst du das je nach dem trotzdem. Und Membervariablen kommen nicht unbedingt auf den Stack! Die kommen dorthin, wo die Klasse erstellt wurde, also womöglich auch auf den Heap. Der Stack ist sowieso begrenzt, man sollte nicht zu viel dort drauf setzen.

    Nexus schrieb:

    Vielleicht hab ich einen falschen Eindruck erweckt, es ist ja nicht so, dass ich ängstlich vor Zeigern und eigener Speicherverwaltung zurückschrecke - ich hab immer noch genügend Orte, wo ich mit new und delete arbeite 😉
    Ich meinte vielmehr, dass eigene Speicherverwaltung halt viele Fehlerrisiken birgt und man viel stärker aufpassen muss. Ich sehe deshalb automatische Speicherverwaltung als "Geschenk" an, das auch eingesetzt werden sollte, wenn es geht ...

    Du hast doch Angst vor den Fehlerrisiken. Aber wenn du sie nie antriffst, dann wirst du immer Angst davor haben. Wenn du automatische Speicherverwaltung als ein "Geschenk" siehst, dann bist du, wie gesagt, in der falschen Sprache. Ich sehe viel eher die nicht automatische Speicherverwaltung als ein wundervolles Geschenk! Sicher, man kann sich damit den ganzen Körper wegsprengen, aber wenn man ein wenig Übung hat, und die sollte man sich aneignen, dann ist das kein Problem mehr.

    Nexus schrieb:

    ... (im Übrigen ist es auch noch schneller). Wie Badestrand in seinem Post gesagt hat, würde ich Stackvariablen gegen "praktische" Vorwärtsdeklarationen lieber nicht eintauschen.

    Stackvariablen können nur temporär erstellt werden oder müssen kopiert werden. Klar bei der Erstellung ist der Stack schneller, wenn du aber danach immer kopieren musst, ist die Übergabe eines Zeigers deutlich schneller, da du auf dem Heap nur ein einziges Mal allokierst.

    Nexus schrieb:

    Hm... Was meinst du genau mit "Optionen"? Ich hab das Gefühl, wir stellen uns unter einer Masterklasse nicht ganz das Gleiche vor.

    Scheint, dass du noch viel mehr darunter verstehst als ich.

    Nexus schrieb:

    Bei mir ist es so, dass nur die ganz zentralen Dinge dort geregelt werden.

    Alles? 🙂

    Nexus schrieb:

    Der Master ist bezeichnenderweise (sorry, wusste keinen besseren Namen als "Master" :)) die oberste Direktive, die alles regelt. Er überwacht den Verlauf des Programms und gibt den einzelnen Oberflächen (abstrakte Basisklasse Surface ) die Kontrolle, wenn eine entsprechende Eingabe getätigt wurde. Abgesehen von der Kontrollfunktion besitzt er noch einige für Grafikroutinen benötigte Variablen (z.B. das Fenster, oder Event für Eingaben, Schriftarten), dient also auch als Ersatz für globale Variablen.

    Eindeutig, alles 😉
    Schon nur das "Ersatz für globale Variablen" zeigt auf, dass da was nicht stimmen kann. Globale Variablen braucht man nicht und man braucht auch kein Ersatz dafür. Deshalb ist das Singleton-Pattern auch so umstritten, weil es oft als Ersatz für globale Variablen herangezogen wird, was es nicht sein sollte.

    Nexus schrieb:

    Aber ganz dezentral kannst du das Programm ja auch nicht steuern (ich nehme nicht an, dass du sehr vieles in der main() -Funktion stehen hast), oder? Ich hab bei mir gerade mal zwei Funktionen in main() , nämlich eine für die Initialisierung und eine für den ständigen Verlauf.

    Ich habe normalerweise kaum etwas in der Main, weil ich eben dezentral programmiere. Wenn ich viel in die Main schreiben würde, dann würde diese zu einem zentralen Punkt werden, nicht?

    Aber man kann dezentral programmieren, man muss nur genügend aufsplitten. Gerade deine Master und Game Klassen sind für mich eindeutige Hinweise darauf, dass du noch nicht genügend gesplittet hast.

    Aber mal ein wenig allgemeiner und ich bitte dich, die Frage nicht böse zu verstehen. Wieviel hast du in C++ schon gemacht? Und wieviel hast du schon zu C++ gelesen, welche Bücher? Versteh mich bitte nicht falsch, aber ich habe ein wenig das Gefühl, dass ein Spiel zu programmieren, vielleicht eine Stufe zu hoch ist.

    So, das war nun wirklich ein riesiger Post. Ich könnte noch mehr schreiben, muss aber essen gehen und möchte auch noch selber heute was programmieren 😃

    Grüssli



  • Versteh mich bitte nicht falsch, aber ich habe ein wenig das Gefühl, dass ein Spiel zu programmieren, vielleicht eine Stufe zu hoch ist.

    So, wie ich Nexus einschätze, reicht sein können für ein einfaches Spiel allemale. Sein Problem ist hald, wie ich vermute, dass er sich im vornherein zu viele Gedanken macht.
    Imhos sollte er einfach mal anfangen und dann wird er früher, oder später merken, was an dem Design Mist ist. Das prägt sich dann auch mehr ein und man kennt Alternativen. (Weil es hier vlt. schlecht war, heisst ja nicht, dass es wo anderst nicht mal von Nutzen sein kann).

    Hast du demnach auch das Problem mit langen Kompilierzeiten? Oder sind deine Projekte einfach so riesig?

    Es ist mittlerweile Recht gross geworden. (Die grösse .cpp hat ca. 1500 Zeilen. ) 🙂

    Um da jetzt mal den Vergleich zu machen. Dort ist mein gesamtes GUI System drin. Und das habe ich imho schon recht gut gemacht, aber ich sage dir, wenn ich, dass ich am liebsten alles nochmal neu schreiben würde, weil so richtig gefällt mir das ganze eigl. nicht. Aber ich habe auch keine Lust das ganze nochmal zu machen, vor allem, da ich dann wahrscheinlich auch nicht 100% zufrieden bin. 😉 - Ich denke mal, dass es da vielen gleich geht. Man ist irgendwie nie richtig zufriede mit dem, was man hat. 🙂



  • Dravere schrieb:

    Das bedeutet für mich eigentlich nur, dass du noch nicht genügend aufgesplittet hast. Dann gibt es eben Kollisionsobjekte und bewegliche Objekte. Ein Player wäre demnach beides, ein Tile nur ein Kollisionsobjekt. Durch die Auftrennung passiert dann auch der Logikfehler nicht mehr.

    Ja, so könnte man es auch sehen. Doch ist etwas erst richtig objektorientiert, wenn es so weit wie möglich aufgesplittet ist? Ich hab irgendwie das Gefühl, ich würde mit dieser Einstellung nur das Projekt unnötig unübersichtlich machen (im Moment kann ich mir mein Design relativ gut vorstellen und es macht für mich auch einigermassen Sinn von der Logik her).

    Dravere schrieb:

    Das ist nicht nur kompliziert, sondern sogar langsam! Ein dyamic_cast ist teuer, erst recht, wenn er immer wieder ausgeführt wird. Zudem zeigt ein dynamic_cast, wie so oft, darauf hin, dass ein Designfehler vorliegt. Es sollte ohne gehen!
    Ein Spieler ist nicht da, um sich zu bewegen, Regeln sind dafür da. Und das Spiel, welches die Tiles beinhaltet und auch den Spieler hat, sollte mit den Regeln den Spieler verschieben. Es kann also alles intern gelöst werden.

    Du meinst also (falls ich das mit dem Spieler als Eigenschaft von Game durchziehe), dass der Spieler sich selbst nicht um die eigene Bewegung, Kollisionsabfrage, etc. kümmern sollte? Was sind denn seine Aufgaben? Ich hab bisher eher gedacht, jede Klasse solle nur das tun, was auch ihrem Aufgabenbereich entspricht. Also für Game wäre das meiner Meinung nach, dem Spieler die Kontrolle weiterzugeben (Funktion Player::Think() ) und nicht alles selbstständig in die Hand zu nehmen.
    Und was den dynamic_cast betrifft: Ich muss es noch irgendwie hinkriegen, dass man direkt einen Zeiger auf Game hat (also höchstens am Anfang oder gar nie dynamisch gecastet). Oder eben gar keinen Zeiger auf Game selber und es mit Locations oder ähnlich lösen.

    Dravere schrieb:

    Nein. Ich hätte da eher an eine Location gedacht. [...] Wobei man das sicher ausbauen könnte. Vielleicht in das bewegliche Objekt nehmen. Zudem dann überprüfen, ob es eine Kollision gibt oder was auch immer, bzw. ob der Player dort stehen kann. Wenn nicht, muss das Spiel mit den Regeln richtig reagieren und den Spieler anders verschieben. Die Regeln können ja auch als Klassen eingebaut werden. Dann wird einem Regelobjekt der Spieler übergeben und gesagt, er müsse zum Punkt x,y,z gehen. Die Regel probiert das auszuführen und wenn es nicht geht, übergibt sie die Sache anderen Regeln usw.
    Hier werden dann auch nur Zeiger durchgereicht oder Referenzen.

    So was ähnliches wie eine Location (wusste nicht, dass das so heisst) hab ich mir auch schon überlegt. Nur stellte ich mir die Frage, wann ich diese initialisieren sollte, wenn nicht schon zu Beginn? Der Spieler muss ja, sobald er im Spiel ist, mit den Tiles interagieren können.

    Dravere schrieb:

    Wieso hat der Gegner Referenzen auf Spieler? Und wieso überhaupt Referenzen? Wieso nicht Pointer und dann die Übergabe eines Nullpointers erlauben? Ein Spieler könnte keine Waffe haben, ein Spieler oder Gegner kann nirgends stehen.
    Wieso willst du im übrigen alles mit Referenzen lösen? Referenzen kann man nur ein einziges Mal initialisieren, danach kannst du nie mehr ein anderes Objekt zuweisen. Wenn du deinen Klassen immer nur Referenzen übergibst als Member, dann bindest du sie viel zu stark an die entsprechenden Objekte. Das ist meistens gar nicht nötig. Zudem dürfte es Probleme beim "normalen" Kopieren geben.

    Naja, dabei bin ich davon ausgegangen, dass Game eben Container der einzelnen Spielelemente (Gegner, Waffen, Tiles) besitzt und man daher Referenzen übergibt, weil ja immer der gleiche Container referenziert wird und er auch nicht NULL sein kann (im Falle von keinen Gegnern hat man halt einen leeren Container, aber man hat einen).

    Dravere schrieb:

    Das der Spieler gerade im Warteraum ist? Bei den Optionen? In den Highscores? Jedenfalls nicht im Spiel.
    Zudem sollte man viel eher anschauen, was für Vorteile bringt einem eine entsprechende Kapselung. Sollte wirklich das Spiel den Spieler erstellen? Ich würde eher sagen, das Spiel soll mit dem Spieler interagieren. Erstellen tut sich der Spieler wahrscheinlich selbst, zum Beispiel über ein Profil oder ähnliches. Dann kann er den Namen selber festlegen und die Farbe seiner Spielfigur, oder sowas in der Art 😉

    Hier gehen unsere Vorstellungen schon wieder auseinander 😉
    Als Spieler bezeichnete ich nur die Spielfigur selber. Falls ich noch Profile machen würde (was ich momentan nicht vorhabe), würde ich die separat regeln. Und die Spielfigur existiert ja wirklich nur während des Spiels und wird am Ende auch wieder zerstört, also nichts mit Menü, Optionen oder Highscores.

    Dravere schrieb:

    Du hast doch Angst vor den Fehlerrisiken. Aber wenn du sie nie antriffst, dann wirst du immer Angst davor haben. Wenn du automatische Speicherverwaltung als ein "Geschenk" siehst, dann bist du, wie gesagt, in der falschen Sprache. Ich sehe viel eher die nicht automatische Speicherverwaltung als ein wundervolles Geschenk! Sicher, man kann sich damit den ganzen Körper wegsprengen, aber wenn man ein wenig Übung hat, und die sollte man sich aneignen, dann ist das kein Problem mehr.

    Wer sagt, dass ich sie nie antreffe? Ich habe wohl schon genügend Stunden mit Fehlersuche wegen eines fehlerhaften Pointers verbracht :p. Ich denke, ich könne im Weiteren auch von mir behaupten, dass ich mich einigermassen mit Speicherverwaltung auskenne. Klar lernt man immer dazu, und mit Zeigern in Verbindung mit Designfragen habe ich vielleicht nicht so viel Erfahrung, aber mich hat es zum Beispiel auch sehr interessiert, eigene dynamische Container zu schreiben (also die Angst vor Zeigern ist es nicht). Ich schätze Zeiger wirklich sehr, manchmal sind sie unheimlich praktisch, aber ich ziehe Stackvariablen generell eher vor. Und eine andere Sprache wäre auch sonst eher nichts für mich, C++ gefällt mir...

    Dravere schrieb:

    Stackvariablen können nur temporär erstellt werden oder müssen kopiert werden. Klar bei der Erstellung ist der Stack schneller, wenn du aber danach immer kopieren musst, ist die Übergabe eines Zeigers deutlich schneller, da du auf dem Heap nur ein einziges Mal allokierst.

    Naja, ich würde natürlich auch Stackvariablen nicht unnötig kopieren, sondern meistens als Referenz übergeben.
    Mir kommt gerade noch etwas in den Sinn: Vorwärtsdeklarationen haben auch nur den Vorteil, dass im Header keine anderen Klassen benötigt werden, oder? Spätestens wenn die Zeiger initialisiert werden, müssen ja die Klassen auch bekannt sein (also in der Implementierungsdatei), womit man wieder lange Kompilierzeiten hätte.

    Dravere schrieb:

    Eindeutig, alles 😉
    Schon nur das "Ersatz für globale Variablen" zeigt auf, dass da was nicht stimmen kann. Globale Variablen braucht man nicht und man braucht auch kein Ersatz dafür. Deshalb ist das Singleton-Pattern auch so umstritten, weil es oft als Ersatz für globale Variablen herangezogen wird, was es nicht sein sollte.

    Ich hab gedacht, dass ich mit dem Ausdruck "Ersatz für globale Variablen" nicht auf Verständnis stossen würde 😉
    Es geht wie gesagt vor allem um Grafikdinge, die fast überall benötigt werden. Und ich bin der Ansicht, das ist besser halbwegs global (die Klasse bietet ja immer noch Schutz durch Zugriffsspezifizierer) als hunderte von unnötigen und unübersichtlichen Parameterübergaben zu machen. Und nur wegen des Dogmas "globale Variablen und ähnliche Konstrukte sind böse" werde ich sicher nicht darauf verzichten und mich mit ellenlangen Parameterlisten rumschlagen.

    Dravere schrieb:

    Ich habe normalerweise kaum etwas in der Main, weil ich eben dezentral programmiere. Wenn ich viel in die Main schreiben würde, dann würde diese zu einem zentralen Punkt werden, nicht?

    Ja, stimmt auch wieder, ich hab zentral eher im Sinne einer alles verwaltenden Klasse gemeint. Aber ich kann mir trotzdem nicht ganz vorstellen, wie du das beispielsweise löst. Hast du in der main() eine Instanziierung und dann einen Funktionsaufruf, und dann wird alles innerhalb der Klassen weitergegeben?

    Dravere schrieb:

    Aber mal ein wenig allgemeiner und ich bitte dich, die Frage nicht böse zu verstehen. Wieviel hast du in C++ schon gemacht? Und wieviel hast du schon zu C++ gelesen, welche Bücher? Versteh mich bitte nicht falsch, aber ich habe ein wenig das Gefühl, dass ein Spiel zu programmieren, vielleicht eine Stufe zu hoch ist.

    Naja, ich programmiere natürlich als Hobby, bin jedoch sehr interessiert. Ich programmiere etwas mehr als zwei Jahre und denke, ich kenne mich auch einigermassen mit den Grundlagen aus. Auch, was Spieleprogrammierung selber betrifft (also algorithmisches), kenne ich mich schon ein bisschen aus. Gerade Kollisionsabfragen (vor allem auf dreieckige Tiles) finde ich nicht gerade einfach. Das Problem ist halt, dass ich bisher noch nicht viel von modularer Programmierung gewusst habe, und deshalb fast alles, was Designfragen betrifft, relativ neu für mich ist. Jedoch bin ich auch bereit, das zu lernen, daran soll das Spiel sicher nicht scheitern. Bisher hab ich schon einige Spiele programmiert, und ein gutes Spiel impliziert meiner Ansicht nach nicht zwangsläufig ein perfektes Design...
    P.S. Danke, drakon 🙂

    Dravere schrieb:

    So, das war nun wirklich ein riesiger Post. Ich könnte noch mehr schreiben, muss aber essen gehen und möchte auch noch selber heute was programmieren 😃

    Ich bin dir wirklich sehr dankbar, dass du dir extra so viel Zeit für mich nimmst!
    Es sind auch andere Meinungen erwünscht 😉

    drakon schrieb:

    Es ist mittlerweile Recht gross geworden. (Die grösse .cpp hat ca. 1500 Zeilen. )

    Um da jetzt mal den Vergleich zu machen. Dort ist mein gesamtes GUI System drin. Und das habe ich imho schon recht gut gemacht, aber ich sage dir, wenn ich, dass ich am liebsten alles nochmal neu schreiben würde, weil so richtig gefällt mir das ganze eigl. nicht. Aber ich habe auch keine Lust das ganze nochmal zu machen, vor allem, da ich dann wahrscheinlich auch nicht 100% zufrieden bin.- Ich denke mal, dass es da vielen gleich geht. Man ist irgendwie nie richtig zufriede mit dem, was man hat. 🙂

    Das kenne ich nur zu gut. Ich hab ein älteres Spiel von mir (ein Weltraumshooter), von dem man denken könnte, es sei relativ gut gelungen, wenn man es spielt. Wenn man aber den Code anschaut... Der reinste Albtraum 😃
    Das war eben noch zu Zeiten, wo ich noch keinen grossen Wert auf Design etc. gelegt habe... Deshalb probier ich jetzt auch von Anfang an, das ein bisschen zu beachten. Im Nachhinein noch den grundlegenden Aufbau neu zu gestalten ist nahezu unmöglich...

    Hehe, zum ersten Mal die Meldung "Maximal sind 10 Smilies erlaubt". Ich musste daher etwas kürzen...


  • Administrator

    drakon schrieb:

    So, wie ich Nexus einschätze, reicht sein können für ein einfaches Spiel allemale. Sein Problem ist hald, wie ich vermute, dass er sich im vornherein zu viele Gedanken macht.

    Wie gut kennst du denn Nexus? *das schon immer mal fragen wollte*

    drakon schrieb:

    Imhos sollte er einfach mal anfangen und dann wird er früher, oder später merken, was an dem Design Mist ist. Das prägt sich dann auch mehr ein und man kennt Alternativen. (Weil es hier vlt. schlecht war, heisst ja nicht, dass es wo anderst nicht mal von Nutzen sein kann).

    Dem kann man sicherlich zum Teil zustimmen. Nur ob man die Alternativen kennt ist manchmal fraglich. Man denkt, man kenne sie. Tatsächlich gibt es aber vieles, was man noch nicht kennt.

    Nexus schrieb:

    Ja, so könnte man es auch sehen. Doch ist etwas erst richtig objektorientiert, wenn es so weit wie möglich aufgesplittet ist?

    Naja, jein. Sicher nicht so weit wie möglich, man muss schon eine sinnvolle Grenze finden. Du musst nicht die Moleküle und Atome oder gar die Elektronen, Neutronen und Protonen als Klassen darstellen 🙂
    Aber ich denke man sollte ruhig ein wenig mehr aufsplitten, als zu wenig. Es vereinfacht einem auch später Ergänzungen zu erstellen. Sonst müsste man plötzlich neue Bereiche aufsplitten und das kann sehr mühsam werden.

    Nexus schrieb:

    Ich hab irgendwie das Gefühl, ich würde mit dieser Einstellung nur das Projekt unnötig unübersichtlich machen (im Moment kann ich mir mein Design relativ gut vorstellen und es macht für mich auch einigermassen Sinn von der Logik her).

    Das ist ein Trugschluss, dem ich leider früher auch verfallen war. Durch eine sinnvolle und bessere Aufsplittung schafft man mehr Ordnung im Projekt. Es sind dann mehr Klassen da, aber deutlich besser geordnet und somit steigt die Übersicht.

    Nexus schrieb:

    Du meinst also (falls ich das mit dem Spieler als Eigenschaft von Game durchziehe), dass der Spieler sich selbst nicht um die eigene Bewegung, Kollisionsabfrage, etc. kümmern sollte?

    Genau!

    Nexus schrieb:

    Was sind denn seine Aufgaben? Ich hab bisher eher gedacht, jede Klasse solle nur das tun, was auch ihrem Aufgabenbereich entspricht. Also für Game wäre das meiner Meinung nach, dem Spieler die Kontrolle weiterzugeben (Funktion Player::Think() ) und nicht alles selbstständig in die Hand zu nehmen.

    Ich weiss nicht ob du die Aufgabe kennst, aber wahrscheinlich schon, da sie sehr verbreitet ist und leider ein völlig falschen Bild vermittelt. Aber ich will es mal daran probieren zu erklären, wie du es machst und wie man es machen könnte.

    In vielen Übungsaufgaben für Objektorientierung wird das Beispiel der Formen herangezogen. Man hat ein Quadrat, eine Ellipse, ein Rechteck und ein Kreis. Das sind alles Formen, also Shapes. Also wird eine Grundklasse erstellt, mit dem Namen Shape. Und entsprechend Klassen davon abgeleitet, für das Quadrat, für die Ellipse, für das Rechteck, für den Kreis. Das Quadrat und der Kreis werden meistens sogar vom Rechteck, bzw. der Ellipse abgeleitet.
    In der Shape-Klasse hat es eine draw -Methode, welche pur-virtuell ist. Die entsprechenden abgeleiteten Klassen überladen diese Methode und zeichnen sich selbst. Zusätzlich ist jede der vier Formen als Rechteck beschreibbar. Also wird in der Shape-Klasse die Möglichkeit zur Speicherung der Koordinaten hingesetzt. Vielleicht eben schon einmal gehört?

    Und das ist FALSCH!

    Das Problem hier ist, dass das Zeichnen und die Daten in die gleiche Klasse gestopft werden. Dabei sollten diese getrennt werden.
    Es gibt somit immer noch eine Klasse Shape mit der pur-virtuellen Methode draw . Davon abgeleitet wird eine Klasse Rechteck und eine Klasse Ellipse. Man bemerke, dass keine für den Kreis oder das Quadrat abgeleitet werden!
    Zusätzlich wird eine neue Klasse eingeführt. Man könnte sie RechteckDaten oder ähnliches nennen, da es eigentlich genau die Daten für ein Rechteck sind, aber wir nennen sie jetzt mal ShapeData. ShapeData beinhaltet die Daten, welche vorhin in der Klasse Shape waren. Nun wird ShapeData an die draw -Methode übergeben.
    Der Kreis oder das Quadrat, werden jetzt einfach dadurch ausgedrückt, dass man ShapeData eben die richtigen Daten übergibt. Man könnte auch noch zwei freie Funktionen machen, welche ein entsprechendes ShapeData erstellen, also für einen Kreis oder ein Quadrat.

    Sowas kommt auch in den Bereich von MVC (Model - View - Controller), was aber oft nur mit der GUI in Verbindung gebracht wird. Man kann das gleiche Prinzip aber eigentlich auch auf andere Dinge anwenden.

    Um zurück auf dein Spiel zu kommen. Dein Spieler wäre somit nur ein Modell. Eine Art von ShapeData. Dann gibt es irgendwo Controllers und zwar Mehrzahl! Diese verändern die Daten des Spielers. Am Ende gibt es vielleicht noch mehrere Views, welche den Spieler darstellen. Der Spieler macht nichts mehr, er ist nur noch ein Zustand!
    Game kann, muss aber kein Controller sein. Es ist möglich, dass Game nur Regeln besitzt, also andere Objekte, an welche Game den Spieler übergibt. Und die Regeln sind so vernetzt, dass eine Regel weiss, welche andere Regel in einem gewissen Zustand eintritt. Die Regeln sind somit die Controller. Ein Klasse für die Anzeige des Spielers, wird dann natürlich auch noch benötigt.

    Nexus schrieb:

    So was ähnliches wie eine Location (wusste nicht, dass das so heisst) hab ich mir auch schon überlegt. Nur stellte ich mir die Frage, wann ich diese initialisieren sollte, wenn nicht schon zu Beginn? Der Spieler muss ja, sobald er im Spiel ist, mit den Tiles interagieren können.

    Wie man dem sagt, keine Ahnung. Location = Ort, erschien mir logisch 🙂
    Und nein, der Spieler muss doch nicht zu Beginn wissen, wo er steht. Entweder startet man doch ein neues Spiel, dann wird erst festgelegt, wo er startet und entsprechend wird er hingestellt. Wenn man ein Spiel lädt, wird er wahrscheinlich woanders stehen und entsprechend hingestellt 😉

    Nexus schrieb:

    Naja, dabei bin ich davon ausgegangen, dass Game eben Container der einzelnen Spielelemente (Gegner, Waffen, Tiles) besitzt und man daher Referenzen übergibt, weil ja immer der gleiche Container referenziert wird und er auch nicht NULL sein kann (im Falle von keinen Gegnern hat man halt einen leeren Container, aber man hat einen).

    Der gleiche Container? Übergibst du den ganzen Container?

    Nexus schrieb:

    Hier gehen unsere Vorstellungen schon wieder auseinander 😉
    Als Spieler bezeichnete ich nur die Spielfigur selber. Falls ich noch Profile machen würde (was ich momentan nicht vorhabe), würde ich die separat regeln. Und die Spielfigur existiert ja wirklich nur während des Spiels und wird am Ende auch wieder zerstört, also nichts mit Menü, Optionen oder Highscores.

    Da wird eine Antwort wohl überflüssig, wenn man an MVC denkt, da die Spielfigur bei mir nur noch ein Zustand wäre. Deshalb auch anderswo erstellt werden könnte, usw. usf.

    Nexus schrieb:

    Wer sagt, dass ich sie nie antreffe?

    Ich, hast du das nicht gelesen? 🤡

    Nexus schrieb:

    ... aber ich ziehe Stackvariablen generell eher vor.

    Irgendwann musst du mir mal erklären, was du unter Stackvariablen verstehst. Was du alles auf den Stack packst, da müsste schon längsten ein Stackoverflow stackgefunden ... eh stattgefunden ... haben 🙂

    Nexus schrieb:

    Mir kommt gerade noch etwas in den Sinn: Vorwärtsdeklarationen haben auch nur den Vorteil, dass im Header keine anderen Klassen benötigt werden, oder? Spätestens wenn die Zeiger initialisiert werden, müssen ja die Klassen auch bekannt sein (also in der Implementierungsdatei), womit man wieder lange Kompilierzeiten hätte.

    Sobald du ein new machst oder eine Methode verwenden willst, oder dereferenzieren möchtest, dann brauchst du die vollständige Deklaration, ja. Also in der *.cpp hat man meistens dann ein Include der entsprechenden Header-Datei.
    Aber das ist ja der Trick, dass dann die Sache nicht länger geht! Es wird immer nur die eine Übersetzungseinheit übersetzt. Das parsen von ein paar Header fällt da nicht ins Gewicht. Das Kompilieren dagegen ist aufwendig und das machst du dann nur für wenig Quellcode. Der Linker wird dann wahrscheinlich noch ein wenig Zeit benötigen, aber auch nicht wirklich viel.

    Nexus schrieb:

    Und nur wegen des Dogmas "globale Variablen und ähnliche Konstrukte sind böse" werde ich sicher nicht darauf verzichten und mich mit ellenlangen Parameterlisten rumschlagen.

    1. Ellenlange Parameterlisten sind meistens nicht nötig, wenn man das ein wenig sinnvoll strukturiert.
    2. Ich lass dich gerne selber auf die Schnauze fallen, da habe ich kein Problem damit. 😃
    Bin schliesslich auch selber auf diese gefallen, bis ich es endlich nicht mehr gemacht habe.

    Nexus schrieb:

    Ja, stimmt auch wieder, ich hab zentral eher im Sinne einer alles verwaltenden Klasse gemeint. Aber ich kann mir trotzdem nicht ganz vorstellen, wie du das beispielsweise löst. Hast du in der main() eine Instanziierung und dann einen Funktionsaufruf, und dann wird alles innerhalb der Klassen weitergegeben?

    Meistens sieht das irgendwie so aus:

    int main()
    {
      App* app = new App(); // Allenfalls die parameter weitergeben von der main, wenn man sie möchte.
      app->init(); // oder app->start(); oder app->startup();
      // Ich konnte bisher noch nie wirklich einig mit mir werden xD
    
      delete app;
    }
    

    Manchmal kommt die App auch auf den Stack, kommt drauf an, wieviel Informationen bereits in der App gekapselt sind.

    In der App werden dann alle weiteren Klassen initialisiert, meistens schon bei der Konstruktion. Und die einen Klassen haben dann wieder Klassen in sich drin, bzw. sind abhängig. Oder gewisse werden noch nicht gebaut und erst wenn sie benötigt werden. Kommt alles ein wenig drauf an, was für ein Programm es wird. Eine Masterklasse gibt es aber definitiv nicht. App ist vielleicht eine zentrale Klasse, weil mit ihr alles startet. Im Verlauf des Programmes wird aber kaum noch auf sie zurückgegriffen, weil App schon dafür sorgt, dass alle anderen Klassen korrekt vernetzt sind.

    Nexus schrieb:

    Naja, ich programmiere natürlich als Hobby, bin jedoch sehr interessiert. Ich programmiere etwas mehr als zwei Jahre und denke, ich kenne mich auch einigermassen mit den Grundlagen aus. Auch, was Spieleprogrammierung selber betrifft (also algorithmisches), kenne ich mich schon ein bisschen aus. Gerade Kollisionsabfragen (vor allem auf dreieckige Tiles) finde ich nicht gerade einfach. Das Problem ist halt, dass ich bisher noch nicht viel von modularer Programmierung gewusst habe, und deshalb fast alles, was Designfragen betrifft, relativ neu für mich ist. Jedoch bin ich auch bereit, das zu lernen, daran soll das Spiel sicher nicht scheitern. Bisher hab ich schon einige Spiele programmiert, und ein gutes Spiel impliziert meiner Ansicht nach nicht zwangsläufig ein perfektes Design...

    2 Jahre programmiert und noch nie modular? 2 Jahre C++? Kann man ja fast nicht glauben 😃
    Und was hat du schon als Bücher über C++ gelesen? Die sind nämlich auch noch wichtig. Die können einem ganz neue Sichtweisen geben und man macht riesige Schritte nach vorne.

    Und nein, ein gutes Spiel hängt meistens nicht vom Code dahinter ab. Aber die Wartung und Erweiterung des Spieles schon 🙂
    Und teilweise auch die Lauffähigkeit, was Geschwindigkeit und Bugs betrifft 😉

    Nexus schrieb:

    Ich bin dir wirklich sehr dankbar, dass du dir extra so viel Zeit für mich nimmst!

    Immer wieder gerne. Es ist auch schön, wenn jemand die Tipps ernst nimmt und sich was überlegt.

    Nexus schrieb:

    Es sind auch andere Meinungen erwünscht

    Da wäre ich auch froh drum. Ich bin schliesslich auch nicht der Ober-C++-Guru.

    drakon schrieb:

    Ich denke mal, dass es da vielen gleich geht. Man ist irgendwie nie richtig zufriede mit dem, was man hat.

    Nexus schrieb:

    Das kenne ich nur zu gut. Ich hab ein älteres Spiel von mir (ein Weltraumshooter), von dem man denken könnte, es sei relativ gut gelungen, wenn man es spielt. Wenn man aber den Code anschaut... Der reinste Albtraum

    *das auch kennt*

    Nexus schrieb:

    Hehe, zum ersten Mal die Meldung "Maximal sind 10 Smilies erlaubt". Ich musste daher etwas kürzen...

    *ist soeben auch passiert* ... :=) <- ausgetrickst

    Grüssli



  • Ich glaube ich habe hier noch nie eine Unterhaltung gesehen, wo bei jedem Post so viel drin steckt. 🙂

    Dravere schrieb:

    Wie gut kennst du denn Nexus? *das schon immer mal fragen wollte*

    Naja. Eigentlich gar nicht, aber ich weiss, dass er sicher genügend Fitt ist, um ein kleines Spiel zu schreiben. Um es mal so auszudrücke: "Ich bin erstaunt, was Leute ohne eigentlich viel Erfahrung mit C++ zu haben anschaubare Spiele bringen können." (Also vom Ergebnis her). Sprich sollte das meiner Einschätzung nach bei ihm auch gut gelingen. 🙂
    Aber warum "schon immer mal fragen wollt" ?

    Dravere schrieb:

    Nur ob man die Alternativen kennt ist manchmal fraglich. Man denkt, man kenne sie. Tatsächlich gibt es aber vieles, was man noch nicht kennt.

    Ja, klar geht es darum. Ich meine nur, dass er einfach mal etwas auf eine Art machen soll. Dann merkt man im Nachhinein, dass etwas anderes, was man da hald noch nicht kannte besser gewesen wäre und setzt es dann auf diese Art um. Ein andermal macht man sich vlt. Gedanken und merkt, dass dort die erste Möglichkeit viel mehr bietet, als die zweite Variante. Wenn man jetzt von Anfang an von jemanden vorgesagt bekommt hätte, was man nehmen soll, wäre man das zweite mal nicht von selbst draufgekommen. So meine ich das. Man lernt selber mehr.

    😮 Ich merke auch, wie ihr mich verleitet so viel zu posten. So Schluss. Habe noch anderes zu tun. 😃



  • drakon schrieb:

    Ich glaube ich habe hier noch nie eine Unterhaltung gesehen, wo bei jedem Post so viel drin steckt. 🙂

    Das geht mir gleich. Ich finde es wirklich toll, wenn man mal eine so ausgeprägte Diskussion führen kann.

    Dravere schrieb:

    Aber ich denke man sollte ruhig ein wenig mehr aufsplitten, als zu wenig. Es vereinfacht einem auch später Ergänzungen zu erstellen. Sonst müsste man plötzlich neue Bereiche aufsplitten und das kann sehr mühsam werden. [...] Es sind dann mehr Klassen da, aber deutlich besser geordnet und somit steigt die Übersicht.

    Okay, danke. Den Rat werde ich mir merken. Ich dachte bisher halt einfach, dass man Code möglichst so designen sollte, sodass man sich die Klassenabhängigkeiten gut vorstellen kann und auch die Übersicht behält. Aber das werd ich wahrscheinlich schon noch lernen...

    Dravere schrieb:

    Um zurück auf dein Spiel zu kommen. Dein Spieler wäre somit nur ein Modell. Eine Art von ShapeData. Dann gibt es irgendwo Controllers und zwar Mehrzahl! Diese verändern die Daten des Spielers. Am Ende gibt es vielleicht noch mehrere Views, welche den Spieler darstellen. Der Spieler macht nichts mehr, er ist nur noch ein Zustand!
    Game kann, muss aber kein Controller sein. Es ist möglich, dass Game nur Regeln besitzt, also andere Objekte, an welche Game den Spieler übergibt. Und die Regeln sind so vernetzt, dass eine Regel weiss, welche andere Regel in einem gewissen Zustand eintritt. Die Regeln sind somit die Controller. Ein Klasse für die Anzeige des Spielers, wird dann natürlich auch noch benötigt.

    Vielen Dank für das anschauliche Beispiel mit den Shapes. Dieses MVC-Konzept war mir bis jetzt noch ziemlich unbekannt. Ich hab zwar schon davon gehört, aber mich nie genauer damit befasst. Du verstehst sicher, dass ich das natürlich auch hinterfrage 😉 - Ich meinte, auch schon gehört zu haben, in der OOP würde jede Klasse ihren sehr engen Aufgabenbereich haben, und falls andere Klassen involviert sind, sollten diese ihre Aufgaben selber regeln. Das scheint demnach ein kompletter Irrtum zu sein, oder? Was wäre denn schlimm daran, wenn Player sich selber verwalten würde?

    Dravere schrieb:

    Und nein, der Spieler muss doch nicht zu Beginn wissen, wo er steht. Entweder startet man doch ein neues Spiel, dann wird erst festgelegt, wo er startet und entsprechend wird er hingestellt. Wenn man ein Spiel lädt, wird er wahrscheinlich woanders stehen und entsprechend hingestellt 😉

    Bis jetzt bin ich eigentlich immer von meinem Design ausgegangen, also dass Spieler und Tiles mit dem Spiel erstellt werden. Aber sollten dann die Tiles auch unabhängig von Game erstellt werden? Und die Location-Zeiger werden dann im Konstruktor von Game zugewiesen? Sorry, ich blick da gerade überhaupt nicht durch, für mich ist es mehr verwirrend, wenn alles unabhängig erstellt wird 🙂

    Dravere schrieb:

    Der gleiche Container? Übergibst du den ganzen Container?

    Momentan übergeb ich eben noch einen Zeiger auf Game , sodass man indirekt auf die Member (Gegner, Tiles, etc.) zugreifen kann. Aber falls ich den Container direkt übergeben würde, würde ich das per (Const-)Referenz tun.

    Dravere schrieb:

    Da wird eine Antwort wohl überflüssig, wenn man an MVC denkt, da die Spielfigur bei mir nur noch ein Zustand wäre. Deshalb auch anderswo erstellt werden könnte, usw. usf.

    Steht MVC für vollständige Unabhängigkeit? Wenn ein Spieler (auch nur als Zustand) nur während der Lebensdauer eines Spiels Sinn macht, könnte er doch auch mit ihm erstellt werden, oder? Ansonsten muss man halt jedes Mal vor der Instanziierung von Game noch andere Routinen aufrufen...

    Dravere schrieb:

    Irgendwann musst du mir mal erklären, was du unter Stackvariablen verstehst. Was du alles auf den Stack packst, da müsste schon längsten ein Stackoverflow stackgefunden ... eh stattgefunden ... haben 🙂

    Stackvariablen sind für mich Variablen, die ohne new und delete auskommen und deren Speicher automatisch verwaltet wird (können eigentlich auch auf dem Heap sein). Und ich mach längst nicht alles auf dem Stack, gerade z.B. die polymorphen Oberflächen und einige andere Instanzen werden ja dynamisch allokiert.

    Dravere schrieb:

    Sobald du ein new machst oder eine Methode verwenden willst, oder dereferenzieren möchtest, dann brauchst du die vollständige Deklaration, ja. Also in der *.cpp hat man meistens dann ein Include der entsprechenden Header-Datei.
    Aber das ist ja der Trick, dass dann die Sache nicht länger geht! Es wird immer nur die eine Übersetzungseinheit übersetzt. Das parsen von ein paar Header fällt da nicht ins Gewicht. Das Kompilieren dagegen ist aufwendig und das machst du dann nur für wenig Quellcode. Der Linker wird dann wahrscheinlich noch ein wenig Zeit benötigen, aber auch nicht wirklich viel.

    Genau, das hab ich irgendwie wieder vergessen oder verdrängt 😉

    Dravere schrieb:

    Nexus schrieb:

    Und nur wegen des Dogmas "globale Variablen und ähnliche Konstrukte sind böse" werde ich sicher nicht darauf verzichten und mich mit ellenlangen Parameterlisten rumschlagen.

    1. Ellenlange Parameterlisten sind meistens nicht nötig, wenn man das ein wenig sinnvoll strukturiert.
    2. Ich lass dich gerne selber auf die Schnauze fallen, da habe ich kein Problem damit. 😃
    Bin schliesslich auch selber auf diese gefallen, bis ich es endlich nicht mehr gemacht habe.

    Ich kann mir gut vorstellen, dass es so nicht gut ist, aber eben: Ich probiers so lange aus, bis ich selber merke, dass das nicht gut gehen kann (auf die Schnauze falle) 😃
    Aber ich denke, dieser Vorgang ist - wie drakon sagte - auch normal und gerechtfertigt. Klar, einige Alternativen kommen einem vielleicht selber nie in den Sinn, aber der Lerneffekt ist sicher grösser, wenn man selber auf Probleme trifft. Trotzdem versuche ich natürlich, alle Ratschläge zur Kenntnis zu nehmen!

    Dravere schrieb:

    Meistens sieht das irgendwie so aus:
    [...]
    In der App werden dann alle weiteren Klassen initialisiert, meistens schon bei der Konstruktion. Und die einen Klassen haben dann wieder Klassen in sich drin, bzw. sind abhängig. Oder gewisse werden noch nicht gebaut und erst wenn sie benötigt werden. Kommt alles ein wenig drauf an, was für ein Programm es wird. Eine Masterklasse gibt es aber definitiv nicht. App ist vielleicht eine zentrale Klasse, weil mit ihr alles startet. Im Verlauf des Programmes wird aber kaum noch auf sie zurückgegriffen, weil App schon dafür sorgt, dass alle anderen Klassen korrekt vernetzt sind.

    Also dann ist es mehr eine Abfolge von Initialisierungen (wobei jede Klasse für die nächste zuständig ist)? Dieses System kann ich mir in meinem Projekt jetzt nicht gut vorstellen, es kann jedoch gut sein, dass ich es auch einmal anwenden werde...

    Dravere schrieb:

    2 Jahre programmiert und noch nie modular? 2 Jahre C++? Kann man ja fast nicht glauben

    Vielleicht stellst du dir unter 2 Jahren sehr intensives Lernen vor. Aber wie gesagt, ich bin Hobbyprogrammierer. Da gab es Zeiten, da hab ich fast nichts gemacht, und teilweise war ich lange mit Projekten beschäftigt.

    Dravere schrieb:

    Und was hat du schon als Bücher über C++ gelesen? Die sind nämlich auch noch wichtig. Die können einem ganz neue Sichtweisen geben und man macht riesige Schritte nach vorne.

    Die Grundlagen hab ich vor allem mit "C++ - Objektorientiertes Programmieren von Anfang an" gelernt (wobei ich damals die OOP-Kapitel noch nicht so genau angeschaut habe). Bei mir war es so, dass "Grundlagen" damals wirklich ziemlich trivial waren. Das heisst, ich konnte einigermassen prozedural programmieren, und von OOP wusste ich auch noch nicht sehr viel. Ich hab zwar mit Klassen gearbeitet (sogar mit Vererbung), aber wichtige Dinge ausser Acht gelassen. Dann begann ich (ein wenig übereilig), mit SDL grafisch zu programmieren, und da standen halt die Möglichkeiten der Grafikbibliothek und nicht C++-Mittel im Vordergrund. Seit etwa einem halben Jahr interessiert mich C++ wieder mehr, ich hab dann auch ständig dazugelernt. Seit dann habe ich mich ziemlich ausführlich mit Zeigern, Referenzen, der STL, Polymorphie, Templates, Operatorüberladung, ..., und jetzt eben mit modularer Programmierung befasst.
    Vieles hab ich auch durch Anwendung und durch dieses Forum gelernt, teilweise hab ich auch Internettutorials (z.B. das von Shade Of Mine) gelesen. Seit einigen Wochen hab ich "C/C++-Kompendium - Das komplette Programmierwissen für Studium und Job" ausgeliehen. Das ist ein Buch mit etwa 1300 Seiten, das sehr viele Aspekte von C++ anschneidet und mit dem ich viele der oben genannten Möglichkeiten von C++ noch vertiefen konnte.

    Dravere schrieb:

    Und nein, ein gutes Spiel hängt meistens nicht vom Code dahinter ab. Aber die Wartung und Erweiterung des Spieles schon
    Und teilweise auch die Lauffähigkeit, was Geschwindigkeit und Bugs betrifft 😉

    Ja, das kenne ich... Wobei ich mir vorstellen könnte, dass bei meinem aktuellen Design das Spiel schon wartbar ist. Aber wahrscheinlich ist es nur eine Frage der Zeit, bis sich das als Irrtum herausstellt 😃



  • Schreib mal in jeden deiner Header

    #ifdef _MSC_VER
    # pragma once
    #endif
    

    das sollte die Compile-Time bei Änderungen an einem Header enorm reduzieren, wenn du keine vorkompilierten Header benutzt sogar ständig.


  • Administrator

    drakon schrieb:

    Ich glaube ich habe hier noch nie eine Unterhaltung gesehen, wo bei jedem Post so viel drin steckt.

    Immerhin steckt was drin 🙂

    drakon schrieb:

    Aber warum "schon immer mal fragen wollt" ?

    ka, ich hatte irgendwie immer ein wenig das Gefühl, als wenn ihr euch im RL kennen würdet, aber hab ich mich wohl geirrt 😉

    drakon schrieb:

    😮 Ich merke auch, wie ihr mich verleitet so viel zu posten. So Schluss. Habe noch anderes zu tun. 😃

    :p

    Nexus schrieb:

    Ich meinte, auch schon gehört zu haben, in der OOP würde jede Klasse ihren sehr engen Aufgabenbereich haben, und falls andere Klassen involviert sind, sollten diese ihre Aufgaben selber regeln. Das scheint demnach ein kompletter Irrtum zu sein, oder? Was wäre denn schlimm daran, wenn Player sich selber verwalten würde?

    Nein, es ist absolut richtig und wird auch voll durchgezogen. Es ist doch nicht die Aufgabe des Spielers sich zu bewegen, sondern der Spieler muss bewegt werden. Der Spieler ist ein Zustand, die Regeln verändern diesen Zustand.

    Das erfordert teilweise ein wenig ein Knick im Denken, aber es ist eben schon korrekt.

    Nexus schrieb:

    Bis jetzt bin ich eigentlich immer von meinem Design ausgegangen, also dass Spieler und Tiles mit dem Spiel erstellt werden. Aber sollten dann die Tiles auch unabhängig von Game erstellt werden? Und die Location-Zeiger werden dann im Konstruktor von Game zugewiesen? Sorry, ich blick da gerade überhaupt nicht durch, für mich ist es mehr verwirrend, wenn alles unabhängig erstellt wird

    Theoretisch könnten die sehr gut unabhängig erstellt werden. Es kommt da allerdings auch ein wenig drauf an wie man das Strukturiert. Grundsätzlich würde ich persönlich schon auch eher etwas wie eine Map einführen. Die Sache also aus dem Game herauskapseln. So kann man die Maps auch austauschen 😉
    Und man könnte natürlich auch Static-Tiles und Dynamic-Tiles einführen. Zumindest würde ich das nun so nennen. Die Tiles werden ja oft gleich aussehen und womöglich gleiche Eigenschaften aufweisen. So ein Tile, wird nur ein einziges mal erstellt, quasi das Static-Tile. Während die tatsächliche Map aus Dynamic-Tiles besteht. Diese verweisen auf ein Static-Tile. Also ein Dynamic-Tile vereint die Koordinaten mit dem Static-Tile. So spart man auch Speicher!

    Nexus schrieb:

    Steht MVC für vollständige Unabhängigkeit? Wenn ein Spieler (auch nur als Zustand) nur während der Lebensdauer eines Spiels Sinn macht, könnte er doch auch mit ihm erstellt werden, oder? Ansonsten muss man halt jedes Mal vor der Instanziierung von Game noch andere Routinen aufrufen...

    MVC steht für die Trennung von Aufgabenbereichen und dadurch auch das einfache austauschen von Funktionen, Werten oder Ansichten.
    Ja, ein Spieler könnte auch mit dem Spiel erstellt werden, sollte aber nicht vom Spiel abhängig werden 😉
    Und die anderen Routinen rufst du ja auch jetzt schon auf. Nur ist bis jetzt bei dir alles auf einem Haufen. Neu würde das halt alles verteilt werden. Du ordnest halt einen Haufen strukturiert oder halt modular an 🙂

    Nexus schrieb:

    Stackvariablen sind für mich Variablen, die ohne new und delete auskommen und deren Speicher automatisch verwaltet wird (können eigentlich auch auf dem Heap sein). Und ich mach längst nicht alles auf dem Stack, gerade z.B. die polymorphen Oberflächen und einige andere Instanzen werden ja dynamisch allokiert.

    So verstehst du das. Ich würde mit dem Begriff etwas vorsichtiger umgehen. Stackvariablen befinden sich normalerweise auf dem Stack und nicht auf dem Heap. Für Polymorphie braucht es übrigens kein Heap, das kann man auch mit Variablen auf dem Stack machen. Naja und wenn die Variablen auf dem Heap sind, so müssen sie normalerweise auch ein new und delete haben. Nur wird es halt über das Objekt, zu welchem sie gehören, geregelt.
    Bei solchen Variablen muss man aber nicht vergessen, dass man sie extrem bindet. Man kann sie nicht mehr einfach austauschen, was oft ein Nachteil sein kann.

    Nexus schrieb:

    Also dann ist es mehr eine Abfolge von Initialisierungen (wobei jede Klasse für die nächste zuständig ist)? Dieses System kann ich mir in meinem Projekt jetzt nicht gut vorstellen, es kann jedoch gut sein, dass ich es auch einmal anwenden werde...

    Eine Klasse kann auch für mehrere andere Klassen zuständig sein. Und ja, es ist dann eine Art von Baum, der sich selber aufbaut. Er wuchert dann von der Wurzel aus nach oben oder unten. Die Aktionen finden dann aber meistens an den äussersten Spitzen statt.

    Nexus schrieb:

    Vielleicht stellst du dir unter 2 Jahren sehr intensives Lernen vor. Aber wie gesagt, ich bin Hobbyprogrammierer. Da gab es Zeiten, da hab ich fast nichts gemacht, und teilweise war ich lange mit Projekten beschäftigt.

    Naja, ich vergleiches vielleicht mit meinem "Hobbyprogrammieren". Aber ich bin ja so extrem, dass ich kaum mehr nach Aussen gehe und nur noch vor dem Computer sitze. Ich bin ein richtiges Klischee 😃

    Um deine C++ Kentnisse weiter aufzufrischen, empfehle ich ein paar mehr Bücher zu lesen. Vor allem tiefer gehende Literatur, wie zum Beispiel:
    - Die C++ Programmiersprache, von Bjarne Stroustrup
    - Effective C++ und More Effective C++, von ... Name vergessen, zu faul nachzuschauen
    - C++ Templates - The Complete Guide, von David Vandevoorde und Nicolai M. Josuttis.
    - Objektorientierte Programmierung für Dummies, von Marc++us (Gottheit des Forums). Ok, das Buch kann man wohl nicht im direkten Vergleich setzen, aber es ist auch empfehlenswert 🙂

    Vielleicht wäre auch das Lesen von C++ Primer empfehlenswert. Aber das kann ich noch nicht sagen, da ich es mir noch nicht besorgt habe.

    @pragmatiker,
    Besser wäre es gewesen die Include-Guards zu empfehlen. #pragma once ist nichts anders als ein Include-Guard. Allerdings persönlich verzichte ich darauf immer und nehme normale Include-Guards, damit ich Compiler unabhängiger bleibe. Im übrigen denke ich, dass Nexus diese sowieso verwendet und du wahrscheinlich nur eher ein Troll bist ... Denn die Compilezeit wird dadurch nicht verringert! Es werden Fehler verhindert.

    Grüssli



  • ka, ich hatte irgendwie immer ein wenig das Gefühl, als wenn ihr euch im RL kennen würdet, aber hab ich mich wohl geirrt

    Nö. Aber wir haben uns auch schon in einem anderen Forum getroffen. 🙂

    Naja, ich vergleiches vielleicht mit meinem "Hobbyprogrammieren". Aber ich bin ja so extrem, dass ich kaum mehr nach Aussen gehe und nur noch vor dem Computer sitze. Ich bin ein richtiges Klischee

    Och. So geht mir das eigl. auch. 🙂 - Ich freue mich schon, wenn die Prüfungen vorbei sind und ich micht voll und ganz den Computer widmen kann. 😉 - Wen interessiert schon, was das für Wolken über meinem Kopf sind?! - Im Keller regnet es ja nicht. 😃

    Effective C++ und More Effective C++, von ... Name vergessen, zu faul nachzuschauen

    Schande über dich. Scott Meyers, so etwas weiss mach einfach, muss nicht nachschauen. 🙂 (auch noch dazu kann man Effective STL von ihm zählen.).
    Dann kommen noch Bücher von Andrei Alexandrescu (modern C++ Design) und Herb Sutter. ( (More) Exceptional C++, C++ Coding Standards).



  • Ich schreibe immer

    #ifdef _MSC_VER > 1000
       #pragma once
    #endif
    
    #ifndef bla_define
    #define bla_define
    
    class bla {};
    
    #endif //ifndef bla_define
    

    und ich bin mir ziemlich sicher, dass #pragma once effizienter ist, als normale include guards... (d.h., dass es so schneller geht als bei dir...)

    aber lasst euch ma nich stören ^^ ist gerade interessant ;o)

    bb



  • und ich bin mir ziemlich sicher, dass #pragma once effizienter ist, als normale include guards... (d.h., dass es so schneller geht als bei dir...)

    Ja. Das stimmt. Der Compiler kann sich das merken und muss die Datei dann nicht mehr Öffnen, wenn das pragma vorhanden ist. Und afaik unterstützen pragma auch noch andere neuere Compiler, abgesehen von Windows.


  • Administrator

    drakon schrieb:

    Nö. Aber wir haben uns auch schon in einem anderen Forum getroffen. 🙂

    Dann kennt ihr euch aus dem VL.
    Lag ich doch nicht all zu weit daneben. 🙂

    Schande über dich. Scott Meyers, so etwas weiss mach einfach, muss nicht nachschauen. 🙂 (auch noch dazu kann man Effective STL von ihm zählen.).
    Dann kommen noch Bücher von Andrei Alexandrescu (modern C++ Design) und Herb Sutter. ( (More) Exceptional C++, C++ Coding Standards).

    Tut mir leid, ich gebe nicht so viel auf Namen und merke mir diese auch so gut wie nie. Ich habe das wohl nie gelernt, da ich nie irgendwelchen anderen Leuten hinterher gerannt bin 😃
    Aja, modern C++ Design ist wirklich auch noch eine gute Empfehlung. Auch das andere ... bis auf C++ Coding Standards ... davon habe ich noch nie gehört. Und der Titel überzeugt mich jetzt nicht wirklich. Das tönt als möchte jemand anderes mir seinen Standard aufzwingen, wie man Code schreibt. Aber sowas empfinde ich im allgemeinen als etwas sehr subjektives.

    Wegen dem #pragma once ,
    Also ganz ehrlich, zuerst einmal sind andere Dinge, welche bei Nexus die Compilezeit verlängern. Und anderem dem, dass er an zentralen Headern immer wieder herumschreibt :p
    Zweitens kann ich mir schlecht vorstellen, dass dies wirklich ein so extremer Unterschied macht. Erst recht nicht bei den Projektgrössen von Nexus. Und auch sonst, mit heutigen Computern, bzw. Prozessoren und co, kann ich mir schlecht vorstellen, dass da ein merklicher Vor- oder Nachteile zu finden ist. Diese Benchmarks muss mir zuerst mal einer zeigen, bevor ich das glaube. 😉

    Grüssli



  • drakon schrieb:

    Ja. Das stimmt. Der Compiler kann sich das merken und muss die Datei dann nicht mehr Öffnen, wenn das pragma vorhanden ist. Und afaik unterstützen pragma auch noch andere neuere Compiler, abgesehen von Windows.

    Vermutlich kann man einem heutigen Präprozessor getrost zutrauen, daß er in der Lage ist, einen gewöhnlichen Header-Guard als solchen zu erkennen und die Datei infolgedessen nicht zweimal zu laden. #pragma once ist lediglich ein Auswuchs von Microsofts historischer Tendenz, lieber proprietäre Compilererweiterungen zu erfinden, anstatt mit geringfügig mehr Aufwand eine standardkonforme Lösung zu entwickeln.
    Und Windows ist übrigens kein Compiler. SCNR.


Anmelden zum Antworten