21 Stimmen

Einbindung von Header-Dateien / Weiterleitungserklärung

Wann muss ich in meinem C++-Projekt die Einbindung ( #include "myclass.h" ) von Header-Dateien? Und wann muss ich die Vorwärtsdeklaration der Klasse verwenden ( class CMyClass; )?

2 Stimmen

33voto

Charles Beattie Punkte 5419

Versuchen Sie in der Regel zuerst die Vorwärtserklärung. Dies verringert die Kompilierzeiten usw. Wenn sich das nicht kompilieren lässt, wählen Sie die #include . Sie müssen #include verwenden, wenn Sie eines der folgenden Dinge tun müssen:

  1. Zugriff auf ein Mitglied oder eine Funktion der Klasse.
  2. Zeigerarithmetik verwenden.
  3. Verwenden Sie sizeof.
  4. Alle RTTI-Informationen.
  5. new / delete kopieren usw.
  6. Verwenden Sie es nach Wert.
  7. Vererben Sie von ihm.
  8. Haben Sie es als Mitglied.
  9. Instanz in einer Funktion.

(6,7,8,9 von @Mooting Duck)

Wahrscheinlich gibt es noch mehr, aber ich habe heute nicht meinen Sprachrechtshut auf.

4 Stimmen

Sie müssen es auch einschließen, um es nach Wert zu verwenden. Wenn Sie also von ihm erben, ihn als Mitglied haben oder eine Instanz in einer Funktion haben.

2 Stimmen

Um das Auswendiglernen zu erleichtern - alles außer (1) und (4) lässt sich aus "wenn Sie die Größe von wissen müssen CMyClass es Instanz".

14voto

David Punkte 121

Es gibt mehrere Probleme bei der Voranmeldung:

  • Es ist so, als ob Sie Ihren Klassennamen an mehreren Stellen speichern würden - wenn Sie ihn an einer Stelle ändern, müssen Sie ihn nun auch überall anders ändern. Das Refactoring wird zu einer Herausforderung, da der Code mit dem geänderten Klassennamen zwar immer noch gut kompiliert werden kann, das Linking aber fehlschlägt, da die Forward-Deklarationen auf eine undefinierte Klasse verweisen. Wenn Sie die Header-Datei einbinden und keine Forward-Deklarationen verwenden, werden Sie diese Probleme bei der Kompilierung feststellen.

  • Vorausschauende Erklärungen sind für andere schwer aufrecht zu erhalten. Zum Beispiel, wenn eine Header-Datei enthält:

    include "MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h"

    anstelle der Vorwärtserklärung

     class Foo ;  

    ist es für andere leicht zu finden, wo die Klasse Foo deklariert ist. Bei der Vorwärtsdeklaration ist es nicht so Einige IDEs wie Eclipse öffnen die Vorwärtsdeklaration, wenn der Benutzer versucht, die Deklaration zu öffnen. die Deklaration einer Variablen zu öffnen.

  • Das Linken kann mit undefinierten Symbolfehlern fehlschlagen, wenn Sie eine Header-Datei in Ihren Code einbinden, die eine Forward-Deklaration enthält, aber die eigentliche Code-Definition befindet sich in einer anderen Bibliothek, mit der Sie nicht gelinkt haben. Es ist bequemer, dieses Problem zur Kompilierzeit mit Fehlern wie "Could not find file MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h" denn dann wissen Sie, wo Sie die entsprechenden Informationen finden können. Foo.cpp und identifizieren Sie die Bibliothek, die sie enthält.

Wenn Sie der Meinung sind, dass Ihr Build zu lange dauert, dann versuchen Sie, nur zu kompilieren und nicht zu linken. Wenn Ihr Code 10 Sekunden zum Kompilieren und 10 Minuten zum Linken braucht, hat das Problem nichts mit ein paar zusätzlichen Includes zu tun. Wenn Ihre Header-Datei so viel Material enthält, dass sie tatsächlich ein Leistungsproblem verursacht, ist es wahrscheinlich an der Zeit, den Inhalt dieser Datei in mehrere kleinere Header-Dateien umzuwandeln.

Wann ist es also in Ordnung, eine Erklärung weiterzuleiten? Wenn Sie es in derselben Header-Datei tun wie die eigentliche Deklaration.

Exemple :

class Foo ;

typedef Foo* FooPtr ;
typedef Foo& FooRef ;

class Foo
{
   public:
      Foo( ) ;
      ~Foo( ) ;
}

O

class TreeNode ;

class Tree
{
private:
   TreeNode m_root ;
}

class TreeNode
{
   void* m_data ;
} ;

2 Stimmen

Ich stimme den Problemen zu, die @David für Vorwärtserklärungen auflistet. Aber ich stimme nicht mit der Schlussfolgerung überein: "Wann ist es also in Ordnung, eine Vorwärtsdeklaration zu machen? Wenn man es in der gleichen Header-Datei wie die eigentliche Deklaration macht." Wie andere schon gesagt haben, sind Forward-Deklarationen ein wichtiges Werkzeug, um das physische Layout zu entkoppeln und die Builds zu beschleunigen. // Mehr und mehr frage ich mich, ob wir #include "Foo.hf" - .hf für "eine Header-Datei, die nichts außer Vorwärtsdeklarationen enthält." // Natürlich würde ich das automatisch generieren.

0 Stimmen

Ihre Punkte 1 und 3 scheinen ungültig zu sein. Im Grunde ist es dasselbe, wie wenn Sie vorwärts erklären class Foo; in der Kopfzeile und hat nicht #include "Foo.h" in der .cpp-Datei - Sie erhalten den Kompilierungsfehler "Verwendung eines unvollständigen Typs". Wie ist es überhaupt möglich, einen Link-Fehler zu erhalten? Hat das etwas mit vorkompilierten Headern zu tun (damit habe ich keine Erfahrung)?

0 Stimmen

Was Ihren 2. Punkt betrifft - ja, das stimmt irgendwie. Aber das passiert nur, wenn Sie in .h-Dateien navigieren, in .cpps ist alles OK. Und so ziemlich jede IDE hat eine Art "Klassensuche", mit der man eine Klasse anhand ihres Namens finden kann - sie zeigt alle Deklarationen/Definitionen an und normalerweise ist es nicht so schwer, herauszufinden, wo die richtige Definition ist. @KrazyGlew, da David anscheinend StackOverflow verlassen hat, und Sie ihm zugestimmt haben, richte ich diese Fragen an Sie. Könnten Sie das etwas näher erläutern?

11voto

ypnos Punkte 47895

Wenn Sie nur einen Zeiger auf die Klasse benötigen und außer ihrem Namen keine weiteren Informationen über die Klasse benötigen, können Sie die Forward-Deklaration verwenden.

5voto

Als Anfänger sollten Sie Header-Dateien immer #include, wenn Sie die Typen oder Funktionen, die sie enthalten, verwenden müssen - versuchen Sie nicht, Ihren Build zu "optimieren", indem Sie Dinge vordeklarieren - das ist fast nie notwendig, selbst bei großen Projekten, vorausgesetzt, das Projekt ist gut aufgebaut.

Nur in Situationen wie dieser ist eine Vorwärtsmeldung unbedingt erforderlich:

struct A {
   void f( B b );
};

struct B {
   void f( A a );
};

wobei jede Struktur (oder Klasse) auf den Typ der anderen verweist. In diesem Fall benötigen Sie eine Forward-Deklaration von B, um das Problem zu lösen:

struct B;   // forward declaration

struct A {
   void f( B b );
};

struct B {
   void f( A a );
};

1 Stimmen

Die Wartung großer Projekte, die eine große "forward_declarations.h"-Datei enthalten, kann ein Alptraum sein, da sie das Entwicklungswerkzeug oft verwirrt und es schwierig macht, eine unbekannte Codebasis zu durchsuchen. Auch wenn es manchmal wichtig ist, die Kopplung in Ihrem Code zu verringern, sollten Sie nicht einfach automatisch jede Klasse in eine Forward-Dec-Datei packen.

4voto

Pontus Gagge Punkte 16933

Sie sollten bestrebt sein, Ihre Kosten zu minimieren. #include s, um die Kompilierungszeiten zu verkürzen, aber auch um die Modularität und Testbarkeit zu verbessern. Wie @ypnos sagt, sind Klassenforwards hervorragend geeignet, wenn man nur Zeiger benötigt.

Praktische Tipps zur Verringerung von Kopfzeilen-Abhängigkeiten finden Sie z. B. unter 本論文 .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X