Eigene Instanz übergeben



  • Swordfish schrieb:

    In Zeile 4 von cgamestate_menu.hpp oben? Damit Du in Zeile 9 den Zeiger CGame *pcGame; deklarieren kannst, ohne, daß cgame.hpp eingebunden werden muss, was seinerseits wieder cgamestate_menu.hpp einbinden würde, was seinerseits wieder cgame.hpp einbinden würde, was seinerseits wieder ... ad infinitum.

    Achso. Ok vielen Dank. Dann werde ich jetzt überall f.d. benutzten wo es geht. 🙂



  • Sollte ich eigentlich alle Klassen in der main.cpp includen und dann nur noch mit f.d. arbeiten oder die Klassen dort includen wo sie tatsächlich gebraucht werden?



  • Header da includen so sie gebraucht werden!



  • Schlangenmensch schrieb:

    Header da includen so sie gebraucht werden!

    Und dann mit f.d. arbeiten wo es eben gebrauch wird?



  • Wenn Du nur nen Pointer brauchst tut es eine forward declaration. Brauchst Du eine Instanz, brauchst Du die vollständige Definition.



  • Swordfish schrieb:

    Wenn Du nur nen Pointer brauchst tut es eine forward declaration. Brauchst Du eine Instanz, brauchst Du die vollständige Definition.

    Ja, das stimmt natürlich. Ich weiß nur nicht so genau wann ich includen oder f.d. benutzen soll.

    Also mit den Headers ist jetzt klar. Immer dann includen wenn sie gebraucht werden. Die Frage ist jetzt wann f.d. . Halt immer dann, wenn es gebraucht wird und ein includen des Headers keinen Sinn machen würde?



  • Bizarreofnature schrieb:

    Die Frage ist jetzt wann f.d. . Halt immer dann, wenn es gebraucht wird und ein includen des Headers keinen Sinn machen würde?

    Immer dann, wenn nur der Name des Datentyps gebraucht wird und nicht seine vollständige Definition.

    1. Der vollständige Typ T wird gebraucht, wenn eine Klasse definiert wird, die ein Member vom Typ T oder T[] (C-Style-Array) hat.

    2. Eine Forward-Deklaration genügt, wenn eine Klasse definiert wird, die ein Member vom Typ T&, T* oder std::container<T> hat (container = vector, deque, list, ...).

    3. Eine Forward-Deklaration genügt, wenn Methoden definiert werden, die Parameter oder Rückgabewerte vom Typ T, T*, T& oder std::container<T> haben.

    4. Der vollständige Typ wird gebraucht, wenn von T abgeleitet wird.

    5. Der vollständige Typ wird gebraucht, wenn auf Eigenschaften (Methoden oder Membervariablen) von T zugegriffen wird. Ebenso, wenn Instanzen von T gebildet werden oder wenn sizeof(T) abgefragt wird.

    Die Punkte 1 bis 4 betreffen in der Regel Klassen-Definitionen und damit Header-Dateien. Punkt 5 betrifft die Implementation und kann daher in der Regel in der cpp-Datei erledigt werden, außer bei Templates.

    Die Liste ist bestimmt nicht vollständig.



  • edit



  • Super, vielen Dank 🙂



  • Printe schrieb:

    (Liste, wann includes und forward-decls benutzt werden)

    Schöne Liste. Aber ich gehe meist anders vor:
    1. sicherstellen, dass die .cpp-Datei als allererstes die zugehörige .h-Datei includet
    2. keine unnützen Header einbinden
    3. Mit forward-Dekl. gehe ich sparsam um und verwende die eigentlich nur, wenn es sich lohnt. Sofern Compilezeit kein großes Problem ist, einfach die passende .h einbinden und forward-Dekl. nur sparsam bzw. für zirkuläre Bezüge, von denen es hoffentlich nur wenige/keine gibt, nutzen.
    4. Wenn man häufiger merkt, dass man eigentlich nur diverse Fwd-Dekl. aus einem bestimmten Bereich braucht, ggf. einen whatever_fwd.h -Header erzeugen, der ne gesammelte Liste nur mit den entsprechenden Forward-Deklarationen enthält.

    Ich finde nämlich, dass

    namspace foo {
    namespace bar {
    class Baz;
    } // namespace bar
    } // namespace foo
    

    sehr viel umständlicher zu lesen ist als

    #include "foo/bar/Baz.h"
    

    oder auch

    #include "foo/bar_fwd.h"
    

    Wenn man viele Forwards macht, kann man auch leicht mal die Übersicht verlieren, wenn z.B. eine Klasse in einen anderen Namespace verschoben wird.



  • Danke für die Antwort. Ich freue mich sehr über diese Infos, weil ich einen sauberen Quelltext haben will. Programmieren konnte ich schon länger, aber wie 😃

    Noch eine Frage, da es eh gerade um Instanzen von Klassen geht..

    Wie schreibe ich diese in eine Klasse? z.B. die Klasse "CTest"

    class Cbla
    {
    	private:
    		CTest cTest;
            CTest *pcTest;
    };
    

    oder

    class Cbla
    {
    	private:
    		CTest m_cTest;
            CTest *m_pcTest;
    };
    


  • Ich würde mir zunächst Gedanken um das unsinnige C in CTest machen ...



  • manni66 schrieb:

    Ich würde mir zunächst Gedanken um das unsinnige C in CTest machen ...

    Verbesserungsvorschläge?



  • Du meinst, ob du die Namen von Membervariablen mit m_ prefixen sollst?

    Das wird durch den Styleguide des Unternehmens oder Teams vorgegeben, in dem man arbeitet. Und wenn nicht, ist es Geschmackssache.

    Meine Privatmeinung ist: Grundsätzlich sind Prefixe unnötig, Ausnahmen bestätigen die Regel. Begründung:

    * Leichter lesbar ist der Code auf jeden Fall ohne dieses m_lpcsz-Gedöns.
    * Leichter schreibbar auch.
    * Geprefixte Namen sind Überbleibsel aus den 90er Jahren; besonders Microsoft hat hier viel Unheil angerichtet mit seiner Ungarischen Notation, die einfach nicht totzukriegen ist. Moderne IDEs wissen jederzeit, für welche Art Dingens (Membervariable, Stackvariable, Funktion, Datentyp etc.) ein Bezeichner steht, und zeigen das durch Syntax-Highlighting oder bei Mouse-Over völlig ausreichend an. Editoren, die das nicht können, gehören auf den Müll.
    * Wird der Typ einer Variablen geändert, dann muss bei geprefixten Namen auch der Name angepasst werden, sonst sind Name und Typ nicht mehr konsistent.
    * Auch Auto-Completion wird eher umständlicher, wenn alle Bezeichner gleich anfangen.



  • Uff du hast es ziemlich auf den Punkt gebracht.
    Mein jetztiges Spiel programmiere ich auch mittels Ungarische Notation.
    Jetzt schäm ich mich fast 😃





  • manni66 schrieb:

    Ich würde mir zunächst Gedanken um das unsinnige C in CTest machen ...

    hahaha "unsinnig". so ein quatsch. C/I/S/E hat natürlich seine berechtigung. bei p/i/c und dem zeug bei variablen sehe ich kritik ein.



  • manni_666 schrieb:

    manni66 schrieb:

    Ich würde mir zunächst Gedanken um das unsinnige C in CTest machen ...

    hahaha "unsinnig". so ein quatsch. C/I/S/E hat natürlich seine berechtigung. bei p/i/c und dem zeug bei variablen sehe ich kritik ein.

    I (für interface) halte ich für berechtigt, um Schnittstellen sichtbar von Klassen abzugrenzen. In C++ ist das leider nur durch Bezeichner-Konventionen möglich, weil Klassen und Interfaces syntaktisch dasselbe sind.

    Die anderen (C für class, S für struct und E für enum) halte ich für verzichtbar. Kannst du Argumente dagegen nennen?



  • Printe schrieb:

    manni_666 schrieb:

    manni66 schrieb:

    Ich würde mir zunächst Gedanken um das unsinnige C in CTest machen ...

    hahaha "unsinnig". so ein quatsch. C/I/S/E hat natürlich seine berechtigung. bei p/i/c und dem zeug bei variablen sehe ich kritik ein.

    I (für interface) halte ich für berechtigt, um Schnittstellen sichtbar von Klassen abzugrenzen. In C++ ist das leider nur durch Bezeichner-Konventionen möglich, weil Klassen und Interfaces syntaktisch dasselbe sind.

    Die anderen (C für class, S für struct und E für enum) halte ich für verzichtbar. Kannst du Argumente dagegen nennen?

    S sagt mir es handelt sich lediglich um einen "container" für daten. wahrscheinlich keine getter/setter, dafür direkter zugriff auf die member.
    wenn ich eine funktion sehe, die "Type x" als parameter hat, kann das ein template type sein, ein typedef oder macro. "EType" würde mir direkt genaueres sagen.
    das C halte ich vor allem für einen konsequent schritt zur einheitlichkeit und somit weniger umdenken.

    natürlich kann man auch alles weglassen und namen wie "window_mousehandler_callback_interface" nutzen 😃



  • manni_666 schrieb:

    S sagt mir ...
    "EType" würde mir ...

    Gut, wenns dir hilft. Ich lass mir da gern von meiner IDE helfen, die sagt mir zu jedem Datentyp sofort, was es ist. "Und was ist, wenn du die IDE mal nicht da hast" lasse ich nicht gelten - die habe ich immer da, die ist nämlich Open Source.

    das C halte ich vor allem für einen konsequent schritt zur einheitlichkeit und somit weniger umdenken.

    Was konsequent und einheitlich ist, kommt stark auf den Standpunkt an. Wenn das das einzige Argument für das C ist, kann ich nur sagen: Nicht überzeugend.

    Mich störts, wenn in meinem Klassen-Browser alles mit C anfängt. Als ob ich zu doof wäre, zu merken, dass das Klassen sind ...

    natürlich kann man auch alles weglassen und namen wie "window_mousehandler_callback_interface" nutzen 😃

    Viel zuviele Wörter. Mindestens window und callback sind überflüssig. Ich würde IMouseHandler oder IMouseEvent oder etwas in der Art vorschlagen.


Anmelden zum Antworten