header regeln?



  • Hallo,

    so, da ich gestern mein Projektchen bissel kaputt gemacht habe indem ich mich verheddert habe mit meinen Headerndateien, wollt ich ma fragen ob es "richtilnien" gibt die man einhalten sollte?

    Ich mein gestern hab ich mir ne neue Klasse "Netzwerk" gemacht und wollte die halt in mein Spielchen packen, aber dann hab ich mich so vertan das nichtsmehr ging 😃

    also Netzwerk hat Spieler aufgerufen, was wiederum Netzwerk aufgerufen hat usw.
    Jetzt ja, iregndwie hab ich grad mühe mit dem Problem aber ich denke es liegt einfach daran das ich nicht weis wie ich am inteligentesten include...

    So, gibt es irgendwie richtlinien? was man wie includen soll?

    Danke vielmals!



  • Forward declaration funktioniert auch fuer Typen.



  • Wie schon gesagt forward Deklarationen benutzen.

    Beispiel:

    //spieler.h
    #ifndef SPIELER_H
    #define SPIELER_H
    #include "netzwerk.h"
    class Spieler{
    	Netzwerk *n;
    };
    #endif
    
    //netzwerk.h
    #ifndef NETZWERK_H
    #define NETZWERK_H
    #include "spieler.h"
    class Netzwerk{
    	Spieler *p;
    };
    #endif
    

    Hier siehst du den Konflikt, ohne Netzwerk keinen Spieler und ohne Spieler kein Netzwerk, also kannst du beides nicht includen.
    Lösung:

    //spieler.h
    #ifndef SPIELER_H
    #define SPIELER_H
    class Spieler; //forward declaration
    #include "netzwerk.h"
    class Spieler{
    	Netzwerk *n;
    };
    #endif
    
    //netzwerk.h
    #ifndef NETZWERK_H
    #define NETZWERK_H
    class Netzwerk;
    #include "spieler.h"
    class Netzwerk{
    	Spieler *p;
    };
    #endif
    

    Wenn du jetzt spieler.h includest, dann deklariert er Spieler ohne Netzwerk zu kennen (die forward declaration), includet dann netzwerk.h, was funktioniert, da er Spieler schon kennt und deklariert dann spieler richtig.



  • nwp3 schrieb:

    Lösung:

    //spieler.h
    #ifndef SPIELER_H
    #define SPIELER_H
    class Spieler; //forward declaration
    #include "netzwerk.h"
    class Spieler{
    	Netzwerk *n;
    };
    #endif
    
    //netzwerk.h
    #ifndef NETZWERK_H
    #define NETZWERK_H
    class Netzwerk;
    #include "spieler.h"
    class Netzwerk{
    	Spieler *p;
    };
    #endif
    

    Ne so nicht.
    Die ganzen include weg, weil nur Pointer verwendet werden, da reichen forwards defs.



  • und verdreht hast du es auch noch.



  • Es ist ein Minimalbeispiel. Natürlich kann man sich die Header komplett sparen und die Klassen einfach in die main schreiben.

    Außerdem habe ich das nicht verdreht. Das meintest du:

    //spieler.h
    #ifndef SPIELER_H
    #define SPIELER_H
    class Netzwerk; //forward declaration
    class Spieler{
        Netzwerk *n;
    };
    #endif
    

    Ja, das würde auch gehen. Aber schon das hier geht nicht mehr:

    //spieler.h
    #ifndef SPIELER_H
    #define SPIELER_H
    class Netzwerk; //forward declaration
    class Spieler{
        Netzwerk n;
    };
    #endif
    

    Und wenn wir uns vorstellen, dass es kein Minimalbeispiel mehr ist und es 20 Klassen gibt, dann muss er in 20 Headern 20 forward Deklarationen machen und darauf achten, dass die ohne Pointer zuletzt kommen. Wenn er einfach die eigene Klasse forward deklariert, dann braucht er nur eine Deklaration zu machen und die Reihenfolge ist egal.



  • nwp3 schrieb:

    Wenn er einfach die eigene Klasse forward deklariert, dann braucht er nur eine Deklaration zu machen und die Reihenfolge ist egal.

    Dann muss die eigene Klasse wissen, in welchen Headern sie verwendet wird. D.h. du hast die Information an zwei Orten statt an einem, musst sie bei einer Änderung entsprechend mehrfach anpassen.

    nwp3 schrieb:

    Und wenn wir uns vorstellen, dass es kein Minimalbeispiel mehr ist und es 20 Klassen gibt, dann muss er in 20 Headern 20 forward Deklarationen machen und darauf achten, dass die ohne Pointer zuletzt kommen.

    Dafür sieht man gleich im Header, wovon die Klasse abhängt (durch den vollständigen Typen oder nur durch den Namen). Wenn du tatsächlich so viele Vorwärtsdeklarationen benötigst, ist auch ein Fwd-Header eine Möglichkeit.



  • Nexus schrieb:

    Dann muss die eigene Klasse wissen, in welchen Headern sie verwendet wird.

    Wieso? Sie deklariert sich selbst forward und includet was sie braucht, dafür muss sie gar nichts wissen, das ist ja gerade das gute.



  • nwp3 schrieb:

    Nexus schrieb:

    Dann muss die eigene Klasse wissen, in welchen Headern sie verwendet wird.

    Wieso? Sie deklariert sich selbst forward und includet was sie braucht, dafür muss sie gar nichts wissen, das ist ja gerade das gute.

    Wenn jetzt aber jetzt jemand anders die Klasse forward declaren möchte muss er das auch immer noch selbst machen.
    Das was du machst spart dir gerade mal ein wenig Tipparbeit bei den Klassen, die die diese eine selbst inkludieren muss.

    Im übrigen ist das, was du machst komplett gegen den Sinn von Vorwärtsdeklarationen. Man möchte mit VD Abhängigkeiten (aka includes von Headern) verringern. Das auflösen von zyklische Abhängigkeiten (welche oft ein Hinweise auf schlechtes Design sind) sind da eher ein netter Nebeneffekt.



  • Vielen Dank, werd es später mal testen!



  • nwp3 schrieb:

    Wieso? Sie deklariert sich selbst forward und includet was sie braucht, dafür muss sie gar nichts wissen, das ist ja gerade das gute.

    Sie includet eben nicht nur was sie braucht, sondern alles was irgendwie mal im Header erwähnt wird. Und der Header der deinen Klassenheader einbindet (wahrscheinlich nach dem selben Muster und deshalb unnötigerweise), bindet damit indirekt ein, was dein Klassenheader einbindet. Und alles, was DEN header dann einbindet... Das sind dann include-Kaskaden, wo mal schnell drei- bis vierstellige Anzahl von Inlcudes in einer .cpp zustandekommen, und das nur für ne Handvoll Pointer.

    Deshalb die Regel: Alles, was du nur als Pointer, Referenzen, Funktionsparameter oder Rückgabetypen benutzt, nur forwärts deklarieren und nur was du wirklich brauchst includen.

    nwp3 schrieb:

    Und wenn wir uns vorstellen, dass es kein Minimalbeispiel mehr ist und es 20 Klassen gibt, dann muss er in 20 Headern 20 forward Deklarationen machen und darauf achten, dass die ohne Pointer zuletzt kommen.

    Wenn er 20 Klassen hat und jede jeweils von den 19 anderen abhängig ist, hat er ganz andere Probleme als die Header...
    (Und falls es ausnahmsweise doch mal Sinn machen sollte gibt es precompiled Header für genau solche Probleme)


Anmelden zum Antworten