Frage zu Bekanntmachungen und Headern
-
Ich bastel gerade etwas herum und bin dabei auf etwas gestoßen das ich mir leider nicht genau erklären kann.
Ich habe folgendes Problem, ich habe 2 Klassen, Klasse A und Klasse B, beide haben einen eigenen Header und eine eigene CPP Datei. In beiden CPP Dateien sind jeweils beide header includiert.
Was mir jetzt Kopfzerbrechen bereitet ist folgende begebenheit, beide Klassen haben als Membervariable einen Zeiger auf die jeweils andere Klasse, diese wird ja schon im Header includiert, nun habe ich aber folgendes, wenn ich die jeweils andere Klasse im header bekanntmache arbeitet der compiler anstandslos alles ab und es funktioniert, wenn ich jedoch im header die ehader datei der anderen klasse include, was ja eine deffinition ist die die klasse eigentlich auch bekanntmachen müsste, meckert der compiler sowohl im header als auch in der cpp das er die andere Klasse nicht kennt und somit alle Funktionsaufrufe an die andere Klasse nicht will, obwohl die Header included sind, includen des headers alleine ohne bekanntmachung im header funktioniert erst dann wenn die Klasse eine Variable der anderen Klasse besitzt. Meine Frage dazu ist warum ist das so, sollte das includen des headers nicht die Klasse komplett Bekanntmachen mit allen Funktionen? Handelt es sich dabei um eine Optimierung weil die bekanntmachung schnelelr ist als das Includen und der Compiler hier erzwingen will das man nur included wenn es sein muß und ansonsten mit bekanntmachungen ind en ehadern arbeitet?
-
Junge da blickt ja kein Mensch durch stell hier doch einfach ein Minimalbeispiel rein, dann sieht jeder sofort was du meinst. Ich hab zwar schon ne Vermutung nachdem ich die erste Hälfte gelesen habe, aber wenn ich dein Minimalbeispiel sehe kann ich sofort sagen warum es nicht geht.
-
Ok minimalbeispiel. Klasse A hat einen Zeiger vom Typ Klasse B.
//header A class B; class A { B *pb; };//header A #include "b.h" class A { B *pb; };Meine Frage ist jetzt wieso funktioniert Beispiel 1 und Beispiel 2 nicht, wende ich Beispiel 2 an wird gemeckert das er den Typ von B nicht kennt. Wende ich Beispiel 1 an funktioniert es Tadellos, Beispiel 2 funktioniert nur dann wenn die Klasse zusätzlich eine Membervariable vom Typ B besitzt.
-
Inkludierst du in "B.h" zufällig "A.h"?
-
Das nimmt der Compiler ja nicht an, ich habe in beiden Headern, einen zeiger auf die andere klasse dh in b einen A *pa; und in B einen B *pb; wenn ich im header die jeweils andere Klasse bekannt mache also in b.h class A; schreibe und in a.h class B; schreibe geht alels super includiere ich abebr stattdessen in a den b header und umgedreht funktioniert das nicht, wenn ich aber zusätzlich zum pointer noch eine variable der anderen Klasse habe geht das via include plötzlich.
-
Also dein Minimalbeispiel wie du es dargestellt hast funktioniert, insofern du in b.h kein "#include "a.h"" stehen hast.
Du kannst in b.h, a.h inkludieren oder in a.h b.h inkludieren, aber nicht in jedem header den jeweils anderen.Wenn du sowieso nur einen Zeiger auf A bzw. B hast reicht im Header normalerweise auch eine Forwärtsdeklaration, so lange du keine Inline-Funktionen hast die auf diese Attribute zugreifen.
-
Also um das mal zu sagen, VC verhält sich bei einem solchen Zustand nicht immer gleich.
file1.h#pragma once #include "file2.h" class a { };file2.h
#pragma once #include "file1.h" class b { a _a; };Funktioniert bei mir, wenn ich a _a; zuerst mal auskommentiere, compile und dann wieder reinmache. Beim ersten mal funktionierts nicht.
Da bekomme ich diesen (und folge-)Fehler:error C2146: syntax error : missing ';' before identifier '_a'
Daher würde ich dir immer raten forward decleration und Pointer zu benutzen. Das geht eigl. immer.
-
Ok danke.
-
Übrigens ist es auch ganz sinnvoll so wenig wie möglich zu inkludieren da diese ganzen inlcudes den Kompiliervorgang extrem verlangsamen, das merkt man schon bei recht kleinen Projekten.
Wenn dein Compiler eine Option hat, wie #pragma once, dann benutze sie. Gerade unterm MSVC bringt das enorme Geschwindigkeitsgewinne.
Sei allerdings so nett und benutze weiterhin include-guards und packe ein #ifdef um das Pragma, falls du mal den Compiler wechseln willst.
Wobei das oftmals auch recht schwer ist, da man sehr leicht den Fehler macht die Richtigkeit an dem Fehlerhalten seines Compilers festzumachen.