Was tun, wenn ich C ++ - Header-Dateien hasse?

25

Ich war immer verwirrt über Header-Dateien. Sie sind so seltsam: Sie enthalten eine .h-Datei, die keine .cpp-Datei enthält, aber .cpp-Dateien werden auch kompiliert.

Kürzlich bin ich einem Teamprojekt beigetreten, und natürlich werden sowohl .h als auch .cpp verwendet.
Ich verstehe, dass dies sehr wichtig ist, aber ich kann nicht damit leben, jede Funktionsdeklaration in jeder von mehreren Klassen einzufügen, die wir haben.

Wie gehe ich effizient mit der 2-Datei-Konvention um?
Gibt es Tools, die Ihnen dabei helfen, oder ändern Sie automatisch eine Datei, die wie im folgenden Beispiel aussieht, in .h und .cpp? (speziell für MS VC ++ 2010)

class A
{
...
    Type f(Type a,Type b)
    {
        //implementation here, not in another file!
    }
...
};

Type f(Type a)
{
     //implementation here
}
...
Oleh Prypin
quelle
8
Diese Frage kann verschiedene Ursachen haben. "Warum benötigen wir bei der Verwendung von c ++ Header?" Oder "Glauben Sie, dass eine moderne Sprache, die kompiliert werden soll, Header verwenden sollte?" So wie es ist, hat es "Was mache ich" und "hasse" im Titel, was eine Fülle von Flaggen auslöst.
Tim Post
4
Ihre Frage lässt es scheinen, als ob Sie C ++ nicht verstehen oder wie das von Ihnen verwendete System es kompiliert. Lerne es richtig zu benutzen und stelle dann subjektive Fragen.
David Thornley
31
Ihr erster Satz zeigt an, dass Sie nicht "alles über Überschriften verstehen". Das Einfügen einer .h-Datei bewirkt nicht, dass die entsprechende .cpp-Datei "auch irgendwie kompiliert" wird. Sie kompilieren CPP-Dateien unabhängig voneinander. Wenn Sie die entsprechende CPP-Datei nicht kompiliert haben, schlägt der Linker fehl, wenn Sie eine Kopfzeile ohne entsprechende Objektdatei einfügen.
Paul Butcher
5
Was ist zu tun? Finde eine andere Sprache, wenn sie dich so nervt.
Paul Nathan
5
Über das "Ich kann nicht mit Copy-Paste leben": Immer wenn man eine Funktion aktualisiert, muss man alle Stellen aktualisieren, an denen sie sowieso aufgerufen wird. Da die Aufrufer viel schwerer zu finden sind als die Deklaration in der Header-Datei, ist die Aktualisierung des Headers nur ein kleines Detail.
Sjoerd

Antworten:

15

Schreiben Sie mehr Refactoring Friendly C ++

In C ++ Sie nicht haben , um Header überhaupt. Sie können das gesamte Objekt in einer Datei wie in C # oder Java definieren. C-Entwickler speichern normalerweise nur externe Aufrufe in einer Header-Datei. Alle internen Aufrufe werden in der C-Datei definiert. Ebenso können Sie Ihre C ++ .h-Dateien für die Klassen / Interfaces (rein virtuelle abstrakte Klassen) / etc reservieren. die außerhalb der DLL freigegeben werden sollen. Für interne Klassen / Strukturen / Schnittstellen usw. fügen Sie einfach die benötigte CPP-Datei ein:

#include<myclass.cpp>

Dies scheint nicht der populärste Ansatz zu sein, aber es ist legal C ++. Es wäre definitiv eine Möglichkeit für all Ihren internen Code. Dadurch können sich der interne Code und die Gruppe von Klassen wesentlich radikaler ändern und gleichzeitig eine stabilere Schnittstelle für den Code außerhalb Ihrer Bibliothek / ausführbaren Datei zur Interaktion bereitstellen.

Wenn Sie Ihre gesamte Klasse in einer Datei haben, können Sie leichter tun, was Sie wollen. Es löst nicht das Problem, eine Methode umzubenennen und nach jedem Ort zu suchen, an dem diese Methode aufgerufen wird, stellt jedoch sicher, dass verständlichere Fehlermeldungen angezeigt werden. Es gibt nichts Schlimmeres, als wenn Ihr Header eine Methode in eine Richtung deklariert, aber Sie implementieren sie anders. Anderer Code, der die Header-Datei aufruft, wird ordnungsgemäß kompiliert, und Sie erhalten eine Link-Ausnahme, während die Implementierungsdatei diejenige ist, die sich darüber beschwert, dass die Methode nicht definiert wurde. Wenn Sie jede Methode direkt definieren (in der eigentlichen Klassendeklaration), wird dieselbe Fehlermeldung angezeigt, unabhängig davon, in welcher Datei sie enthalten ist.

Vielleicht möchten Sie sich auch diese Frage ansehen: Gute Refactoring-Tools für C ++

Wie C / C ++ Header- / Implementierungsdateien auflöst

Auf der Basis-C-Ebene (und C ++ baut auf dieser Grundlage auf) deklarieren die Header-Dateien das Versprechen einer Funktion / Struktur / Variablen, die ausreicht, damit ein Compiler die Objektdatei erstellen kann. In ähnlicher Weise deklarieren C ++ - Headerdateien das Versprechen von Funktionen, Strukturen, Klassen usw. Mit dieser Definition reserviert der Compiler Speicherplatz im Stapel usw.

Die C- oder CPP-Dateien haben die Implementierung. Da der Compiler jede Implementierungsdatei in eine Objektdatei konvertiert, gibt es Verknüpfungen zu nicht implementierten Konzepten (was im Header deklariert wurde). Der Linker verknüpft die Hooks mit den Implementierungen in anderen Objektdateien und erstellt eine größere Binärdatei, die den gesamten Code enthält (gemeinsam genutzte Bibliothek oder ausführbare Datei).

VS-spezifisch

Für die Arbeit mit Visual Studio gibt es einige Assistenten, die die Arbeit etwas erleichtern. Der neue Klassenassistent erstellt das passende Paar aus Header- und Implementierungsdateien. Es gibt sogar eine Klassenbrowser-Funktion, mit der Sie neue Methoden deklarieren können. Die Definition wird in den Header und der Implementierungs-Stub in die CPP-Datei eingefügt. Visual Studio bietet diese Funktionen seit mehr als einem Jahrzehnt (sofern ich sie verwendet habe).

Berin Loritsch
quelle
Das Problem ist, dass ich die Klassen ständig stark
ändere
5
@ BlaXpirit: Also, warum modifizierst du die Klassen die ganze Zeit stark? Eine der Ideen hinter OO Design ist es, viele ziemlich stabile Bausteine ​​zu haben. Wenn ich den Unterricht stark modifizieren würde, würde ich gerne eine dynamischere Sprache wie Common Lisp oder Python verwenden.
David Thornley
2
Das ist was ich tue. Ich verbessere / modifiziere die "Bausteine" und
füge
C ++ hat noch nie freundlich umgestaltet. Das Konzept des Refactorings gewann erst an Bedeutung, als es Tools gab, die es wirklich einfach machten, in Java IDEs zu arbeiten. HINWEIS: Diese Funktionen waren für Smalltalk-Entwickler und andere Sprachen verfügbar, wurden jedoch erst dann zum Mainstream, wenn sie für viele Benutzer verfügbar waren. Bisher habe ich noch niemanden gesehen, der das für C ++ intelligent implementiert. Vielleicht Resharper von JetBrains? Ich weiß, dass es C # - und VB-Code unterstützt, aber ich bin nicht sicher, ob es Ihnen C ++ - Refactoring geben wird.
Berin Loritsch
@Berin: Ich habe vor ein oder zwei Jahren nach C ++ - Refactoring-Tools gesucht und zwei Dinge herausgefunden. Sie waren zu der Zeit ziemlich teuer und ich habe keine Testversionen gesehen, daher weiß ich nicht, was sie taten. Außerdem wurde nur mit Emacs gearbeitet, was die Effektivität in einem Visual Studio-Shop einschränken würde.
David Thornley
13

Werden Sie Java-Entwickler.

Wenn Sie wirklich in C ++ weiterentwickeln müssen, können Sie versuchen, eine IDE zu verwenden. Häufig bieten sie einen Mechanismus, mit dem Sie einer Klasse eine Methode hinzufügen können, und die Deklaration wird automatisch in die .h-Datei und die Definition in die .cpp-Datei eingefügt.

Paul Butcher
quelle
2
kthx, ich kenne Java ein wenig, aber Sie können damit keine Win32-DLLs auf niedriger Ebene erstellen, oder?
Oleh Prypin
41
Ich weiß nicht warum, aber "Java-Entwickler werden" klingt irgendwie nach einer Beleidigung: D.
Oliver Weiler
2
Wenn Sie ein niedriges Niveau erreichen möchten, vergessen Sie alles über "einfache Sprachen". Niedrige Kosten für Schweiß und Tränen.
Batibix
5
Keine besonders hilfreiche Antwort.
ChrisF
1
@OliverWeiler Ich empfinde "ein Java-Entwickler werden" nicht als Beleidigung. Ich programmiere sowohl in C ++ als auch in Java, aber bei weitem bevorzuge ich Java, weil es so viel einfacher ist, sich hinzusetzen und funktionierenden (und portableren) Code herauszuholen. Wenn Sie aus irgendeinem Grund das Vorhandensein von Header-Dateien verachten, ist Java möglicherweise die richtige Wahl (obwohl es seltsam ist, dass Sie Header-Dateien hassen würden; ich würde eine Änderung in der IDE in Betracht ziehen).
Trixie Wolf
7

Vielleicht interessieren Sie sich für das Makeheaders- Programm von Hwaci (diejenigen, die SQLite und Fossil betreiben).

Schauen Sie sich auch an, wie Fossilien gebaut werden , um eine Idee zu haben.

Benoit
quelle
5
Der Fragesteller muss die Beziehung zwischen .h und .cpp noch recht gut verstehen.
Job
2
Ich verstehe die Grundlagen. Die Antwort scheint genau das zu sein, was ich brauche.
Oleh Prypin
4

Wenn Sie die ersten Zeilen einer neuen Klasse schreiben, liegt dies normalerweise daran, dass Sie sie zu diesem Zeitpunkt nur an einer Stelle benötigen. Zu einem späteren Zeitpunkt wird es möglicherweise an mehreren Orten verwendet, anfangs ist dies jedoch normalerweise nicht der Fall.

Viele meiner Kurse beginnen oben in der aktuellen CPP-Datei. Wenn es stabil genug ist, um es an mehreren Stellen zu verwenden, schneide ich es in eine Kopfzeile ein. Obwohl die Klasse oft so schnell verschwindet, wie sie erschien.

Sjoerd
quelle
-1

Als Anregung für den Umgang mit C ++ - Header-Dateien ist es üblich, sie ohne Dateierweiterung oder Dateiendung zu verwenden, wie dies bei "GCC" -Bibliotheken der Fall ist.

In diesem Fall empfehle ich die Verwendung eines " .hpp" (oder "unleast"). .hxx") oder des Dateisuffix.

Möglicherweise müssen Sie den Compiler, die Entwicklerumgebung oder das erstellte Programm konfigurieren.

umlcat
quelle
3
Sprechen Sie darüber, wie beim Einfügen einer Datei #include <iostream>? Das ist nicht nur für die GCC-Bibliothek. Tatsächlich ist es im C ++ - Standard von 1997 , Abschnitt 17.3.1.2 definiert. Ich würde es vermeiden, solche Dateien zu benennen. Sie können, aber der Grund, warum die C ++ - Standardbibliothek dies tat, war wahrscheinlich, Namenskonflikte zu vermeiden. Eigentlich finde ich es sehr seltsam, wenn Compiler beim Einfügen eines Headers automatisch ein '.h' hinzufügen, was für mich ziemlich ungewöhnlich ist. Und ich sehe nie jemanden Namensüberschriften ohne Suffix außer der C ++ - Standardbibliothek.
Vedosity
1
Außerdem sollte ich beachten, dass alle Compiler, die ich verwendet habe, mit Ausnahme von borland (das ich so sehr hasse), nicht automatisch ein '.h' oder '.hpp' oder '.hxx' hinzufügen, wenn Sie es versuchen um eine Datei ohne Suffix einzuschließen. Erwarten Sie nicht #include <someclass>, wie #include <someclass.hpp>auf allen Compilern gelesen zu werden . Ihr Code wird kaputt gehen.
Vedosity