Frage zu Header-Dateien
-
Hallo zusammen,
ich bin gerade dabei mich durch ein größereres Projekt durchzuwühlen und bin in C++ noch im Anfangsstadium. Dabei stoße ich das erste mal auf Header-Dateien in denen mehrere Klassen aufgelistet werden bevor der Header-Teil für die tatsächliche Klasse kommt.
Könnt ihr mir kurz beschreiben, in welchen Fällen das notwendig ist ? Ich konnte in keiner Literatur was passendes finden.class ATANCamera; class Map; class MapMaker; class Tracker; class ARDriver; class MapViewer; class System { public: System(); void Run();
-
Das sind Forwärtsdeklarationen.
Damit teilst du dem Compiler mit, dass es diese Klassen gibt, ohne dass du dafür den entspechenden Header einbinden musst. Das musst du dann erst in der cpp-Datei machen, wenn du die Klassen tatsächlich verwendest.
-
Aber welchen Zweck erfüllt das ? Reicht es nicht aus die Header-Datei der jeweiligen Klasse in der cpp-Datei einzubinden ?
-
sneuma12 schrieb:
Reicht es nicht aus die Header-Datei der jeweiligen Klasse in der cpp-Datei einzubinden ?
Wenn eine solche Klasse bspw. als Rückgabewert einer Methode deklarieren willst, reicht das nicht.
-
Du musst die Frage andersherum stellen: warum genügt es, nur die Vorwärtsdeklarationen zu verwenden und nicht die gesamte Klassendefinition (die in der Headerdatei steht)?
EDIT: falsch gelesen. Siehe Antwort von Daddy_felix. Meine Antwort gilt natürlich trotzdem.
Antwort: wenn es egal ist, wie die Klasse im Detail aussieht. Mit einer Vorwärtsdeklaration kannst du beispielsweise Zeiger auf diese Klasse verwenden:
class foo; foo* ptr;In einer Klasse ergibt das natürlich mehr Sinn, da der Pointee in der .cpp definiert werden kann. Hier muss natürlich die gesamte Klasse bekannt sein.
Ein Beispiel (schlechtes Design, don't try this at home):// foo.hpp class foo { foo(); };// foo.cpp #include "foo.hpp" foo::foo() { // some code }// bar.hpp class foo; class bar { bar(); foo* foo_ptr; };// bar.cpp #include "bar.hpp" #include "foo.hpp" bar::bar() { foo_ptr = new foo; }Für Vollständigkeit: Warum ist das schlechtes Design? -> Hier gibt es keinen Grund, foo nicht als direkten Member von bar zu verwenden. Hier muss man noch einen Destruktor, einen Copy-Constructor und Zuweisungsoperator schreiben. Unnötig.
// bar.hpp #include "foo.hpp" class bar { foo f; }
-
Dann mach doch gleich ein besseres Beispiel

// bar.hpp class foo; class bar { barFct(foo* foo_ptr); };
-
Ja, stimmt. Wäre besser gewesen. Naja...
-
Mal abgesehen von Designgründen: Wenn so ein Projekt mal größer wird, kann die Zeit, die fürs Kompilieren draufgeht schon ganz schön lang werden.
Eine Möglichkeit, die Kompilierzeiten kurz zu halten, ist so wenige Header-Dateien wie möglich einzubinden. Wenn eine Klasse z.B. nur als einen Pointer verwende, reicht eine Vorwärtsdeklaration völlig aus, und ich spare mir den ganzen Header einzubinden - und vor allem rekursiv alle anderen Header die von diesem eingebunden werden.Ich würde sogar empfehlen Vorwärtsdeklarationen zu bevorzugen und den Header erst dann einzubinden, wenn es erforderlich ist, dass die Klasse vollständig ausdefiniert ist (kann ziemlich nervig sein das bei einem größeren Projekt nachträglich zu machen).
Finnegan
-
Ja, Vorwärtsdeklarationen FTW!
Gerne auch über spezielle "forward.hpp" Headers die Vorwärtsdeklarationen für alles was in einem Projekt/Modul/Namespace definiert wird enthalten.
enums müssen dann halt ganz in diese "forward.hpp" Header verschoben werden. Das ist hässlich, stellt aber normalerweise kein echtes Problem dar.Nur wenn man nested classes hat, und Zeiger/Referenzen auf diese ausserhalb der deklarierenden Klasse bräuchte, dann muss man halt weinen gehen

// Wäre fein, aber leider nein :( class outer::inner; // Und weil wir gerade dabei sind..., auch leider nein: namespace foo::bar {
-
Dein 2tes 'leider' verstehe ich nicht. Was ist da foo und bar?
-
Na auch wieder "outer" und "inner", nur halt Namespaces:
namespace foo { namespace bar { // Bäh! Viel schöner (UND praktischer) wäre: namespace foo::bar {Das hat jetzt mit Funktionalität nixe zu tun, aber es wäre angenehm.
U.a. könnte man dann die automatische Einrückung von Namespace-Content sinnvoll in Kombination mitProject::Module::SubModuleNamespace-Hierarchien nutzen.
(Wer will schon den ganzen Content in allenProject/Module/SubModule/*.cppFiles 3-fach eingerückt haben, nur weilSubModuleein Namespace in einem Namespace in einem Namespace ist? Und wer will schon 3xnamespaceschreiben müssen dafür?)
-
IIRC gibt's da ein angenommenes Proposal für C+++17 für.
-
Für beides oder nur für die Namespace-Sache?
ps: Sorry wegen OT

-
Nathan schrieb:
IIRC gibt's da ein angenommenes Proposal für C+++17 für.
Es gibt ein Proposal von 2003 das abgelehnt wurde.
-
Gibt auch was aus 2014.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4230.htmlFrage: wie bekommt man raus wie der Status von so einem Proposal ist?
EDIT: ARGH. OK. Auf http://en.wikipedia.org/wiki/C%2B%2B17 ist es unter "expected features" gelistet
Aber wie findest man es allgemein raus, also ohne zufällig auf einer Seite wie Wikipedia etwas darüber zu finden?
-
Schau dir die meeting minutes an