Unterschied zwischen der Implementierung einer Klasse in einer .h -Datei oder in einer .cpp -Datei

StackOverflow https://stackoverflow.com/questions/1809679

  •  05-07-2019
  •  | 
  •  

Frage

Ich habe mich gefragt, welche Unterschiede zwischen der Deklaration und der Implementierung einer Klasse ausschließlich in einer Header -Datei sind, verglichen mit dem normalen Ansatz, bei dem Sie die Klasse im Header protypisieren und in einer effektiven .cpp -Datei implementieren.

Um besser zu erklären, wovon ich spreche, meine ich Unterschiede zwischen dem normalen Ansatz:

// File class.h
class MyClass 
{
private:
  //attributes
  public:
  void method1(...);
  void method2(...);
  ...
};

//file class.cpp
#include "class.h"

void MyClass::method1(...) 
{
  //implementation
}

void MyClass::method2(...) 
{
  //implementation
}

und ein Just-Header sich nähern:

// File class.h
class MyClass 
{
private:
  //attributes
public:
  void method1(...) 
  {
      //implementation
  }

  void method2(...) 
  {
    //implementation
  }

  ...
};

Ich kann den Hauptunterschied erhalten: Im zweiten Fall ist der Code in jeder anderen Datei enthalten, in der er mehr Instanzen derselben Implementierungen generiert, sodass eine implizite Redundanz; Während im ersten Fallcode von sich selbst zusammengestellt wird und dann jeder Anruf auf das Objekt von bezeichnet wird MyClass sind mit der Implementierung in verbunden class.cpp.

Aber gibt es andere Unterschiede? Ist es bequemer, je nach Situation einen Ansatz anstelle eines anderen zu verwenden? Ich habe auch irgendwo gelesen, dass das Definieren des Körpers einer Methode direkt in eine Header -Datei eine implizite Anforderung an den Compiler ist, diese Methode zu inzeilen, oder?

War es hilfreich?

Lösung

Der praktische Hauptunterschied besteht darin, dass, wenn sich die Elementfunktionsdefinitionen im Körper des Headers befinden, natürlich einmal für jede Übersetzungseinheit zusammengestellt werden, die diesen Header enthält. Wenn Ihr Projekt einige hundert oder tausend Quelldateien enthält und die betreffende Klasse ziemlich weit verbreitet ist, kann dies viel Wiederholung bedeuten. Selbst wenn jede Klasse nur von 2 oder 3 anderen verwendet wird, desto mehr Code im Header ist mehr zu tun.

Wenn sich die Mitgliederfunktionsdefinitionen in einer eigenen Übersetzungseinheit (.CPP -Datei) befinden, werden sie einmal zusammengestellt und nur die Funktionserklärungen werden mehrmals zusammengestellt.

Es ist wahr, dass in der Klassendefinition definierte (nicht nur deklarierte) Mitgliedsfunktionen implizit implizit sind inline. Aber inline bedeutet nicht, was die Leute vernünftigerweise vermuten könnten. inline sagt, dass es legal ist, dass mehrere Definitionen der Funktion in verschiedenen Übersetzungseinheiten erscheinen und später miteinander verbunden werden. Dies ist erforderlich, wenn sich die Klasse in einer Header -Datei befindet, die verschiedene Quelldateien verwenden werden, sodass die Sprache versucht, hilfreich zu sein.

inline ist auch ein Hinweis auf den Compiler, dass die Funktion sinnvoll eingebaut werden könnte, aber trotz des Namens ist dies optional. Je raffinierter Ihr Compiler ist, desto besser kann er seine eigenen Entscheidungen über das Inline -Inline -Treffen treffen, und desto weniger nötig ist es für Hinweise. Wichtiger als das tatsächliche Inline -Tag ist, ob die Funktion dem Compiler überhaupt zur Verfügung steht. Wenn die Funktion in einer anderen Übersetzungseinheit definiert ist, ist sie nicht verfügbar, wenn der Anruf daran kompiliert wird. Wenn also etwas den Anruf einbezieht, muss er der Linker sein, nicht der Compiler.

Möglicherweise können Sie die Unterschiede besser erkennen, indem Sie eine dritte Möglichkeit in Betracht ziehen:

// File class.h
class MyClass
{
    private:
        //attributes
    public:
       void method1(...);
       void method2(...);
       ...
};

inline void MyClass::method1(...)
{
     //implementation
}

inline void MyClass::method2(...)
{
     //implementation
}

Jetzt, da die implizite Inline nicht mehr im Weg ist, bleiben einige Unterschiede zwischen diesem "All -Header" -Ansatz und dem Ansatz "Header Plus Quelle". Wie Sie Ihren Code in Übersetzungseinheiten teilen, hat Konsequenzen für das, was passiert, wie er aufgebaut ist.

Andere Tipps

Ja, der Compiler wird versuchen, eine Methode zu inline, die direkt in der Header -Datei deklariert ist, wie:

class A
{
 public:
   void method()
   {
   }
};

Ich kann mir vorstellen, die Annehmlichkeiten bei der Trennung der Implementierung in Header -Dateien zu folgen:

  1. Sie werden keinen Code aufblähen, da der gleiche Code in mehreren Übersetzungseinheiten enthalten ist
  2. Ihre Zusammenstellungszeit verringert sich drastisch. Denken Sie daran, dass für jede Änderung im Header -Datei Compiler alle anderen Dateien erstellen muss, die sie direkt oder indirekt enthalten. Ich denke, es wird sehr frustrierend sein, wenn jemand das gesamte Binärdatum wieder aufbaut, nur um einen Speicherplatz in der Header -Datei hinzuzufügen.

Jede Änderung zu einem Header, der die Implementierung enthält, wird alle anderen Klassen erzwingen, die diesen Header umfassen, um sie neu zu kompilieren und neu zu verbinden.

Da sich die Header seltener als Implementierungen ändern, können Sie durch Einfügen der Implementierung in eine separate Datei eine beträchtliche Kompilierungszeit speichern.

Wie einige andere Antworten bereits erwähnt haben, definieren Sie eine Methode innerhalb der Datei einer Datei class Block veranlasst den Compiler inline.

Ja, das Definieren von Methoden innerhalb der Klassendefinition ist gleichbedeutend mit der Deklaration inline. Es gibt keinen anderen Unterschied. Es gibt keinen Vorteil, alles in der Header -Datei zu definieren.

So etwas ist normalerweise in C ++ mit Vorlagenklassen zu sehen, da die Definitionen der Vorlagenelemente auch in der Header -Datei aufgenommen werden müssen (da die meisten Compiler nicht unterstützen export). Bei gewöhnlichen Nicht-Template-Klassen macht es jedoch keinen Sinn, dies zu tun, es sei denn inline.

Für mich besteht der Hauptunterschied darin, dass eine Header -Datei wie eine "Schnittstelle" für die Klasse ist und den Kunden dieser Klasse mitteilt, was ihre öffentlichen Methoden sind (die von ihnen unterstützten Vorgänge), ohne dass sich die Kunden über die spezifische Implementierung dieser sorgen. Im Sinne ist es eine Möglichkeit, seine Clients von Implementierungsänderungen zu verkörpern, da sich nur CPP -Datei ändert und daher die Kompilierungszeit viel geringer ist.

Einmal in der Vergangenheit habe ich eine Modulabschützin vor Unterschieden in verschiedenen CORBA -Verteilungen erstellt, und es wurde erwartet, dass sie gleichmäßig unter verschiedenen OS/Compiler/CORBA -Lib -Kombinationen funktionieren. Durch die Implementierung in einer Header -Datei wurde es einfacher, es einem Projekt mit einem einfachen Einfügen hinzuzufügen. Die gleiche Technik war garantiert, dass der Code gleichzeitig neu kompiliert wurde, als der Code, den er aufrief, eine Neukompilation erforderte, wenn dh er mit einer anderen Bibliothek oder einem anderen Betriebssystem zusammengestellt wurde.

Mein Punkt ist also, dass wenn Sie eine ziemlich winzige Bibliothek haben, von der erwartet wird, dass sie in verschiedenen Projekten wiederverwendbar und neu kompiliert wird, was sie zu einem Header macht, bietet Vorteile bei der Integration mit einigen anderen Projekten anstatt zusätzliche Dateien zum Hauptprojekt oder eine externe LIB neu zu kompilieren /OBJ -Datei.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top