Basierend auf der Antwort auf diese Frage: Warum funktioniert C ++? Headerdateien und CPP haben
Ich habe die Antworten gesehen und die Antworten verstanden - warum hat sich das nicht durchgesetzt? C # Java?
Weil es eine schnelle, schmutzige und unelegante Lösung für das Problem der Schnittstelle vs. Implementierung ist.
Es beruht vollständig auf dem C-Präprozessor, der über das blutigste Werkzeug in der Schublade verfügt.
Andere Lösungen vermeiden die folgenden Probleme:
Dviljoen denkt, ich bin ziemlich hart dabei, und er hat Recht. Es ist fast ein 40 Jahre altes Design , aus der Zeit der Lochkarten und Papierklebebänder. Es gibt eine unglaubliche Menge an qualitativ hochwertiger Software, die in C / C ++ mit der Source / Header-Datei-Anordnung gebaut wurde, trotz aller oben genannten möglichen Fehler und Probleme.
Weil es bedeutet, Informationen zu kopieren, die Sie aus dem Quellcode erhalten können. Andere Sprachen versuchen, diese Code-Duplizierung zu vermeiden.
In meinen alten C-Tagen habe ich dasselbe gemacht. Ich habe alle Informationen in meinen .c-Dateien gespeichert und ein kleines Tool verwendet, um Header-Dateien von ihnen während des normalen Builds zu generieren.
Im Fall von C # gibt die 3.0 Spezifikation
anWeil eine Assembly ein selbstbeschreibende Einheit der Funktionalität enthält Code und Metadaten, Es besteht keine Notwendigkeit für #include Direktiven und Header-Dateien in C #. Das Öffentliche Typen und Mitglieder in enthalten eine bestimmte Versammlung werden gemacht verfügbar in einem C # -Programm einfach durch Diese Assembly referenzieren wann Kompilieren des Programms.
Weil sie Reste aus der Vergangenheit sind.
Moderne Sprache verwenden das Konzept der Module und Pakete.
Wenn Sie eine Funktion / Klasse verwenden möchten, die in einer anderen Datei definiert ist, importieren Sie diese Datei. Der Compiler ermittelt die Symbole (d. H. Namen), so dass Sie sie verwenden können.
Der C / C ++ - Ansatz: Extrahieren Sie die Funktions- / Klassendefinitionen von Hand und fügen Sie sie in eine andere Datei ein. Führen Sie dann eine Textinklusion dieser Definition überall dort durch, wo Sie sie verwenden möchten.
In C können Sie keine Vorwärtsreferenzen erstellen, dh. Verwenden Sie eine Funktion, die oberhalb ihrer Verwendung noch nicht definiert ist. Header sind dafür ursprünglich gedacht, als Referenzen zur Implementierung.
Ich habe mir die angenommene Antwort der referenzierten Frage angesehen und es ist richtig. Aber heute ist die Geschwindigkeit der Kompilierung ein kleines Problem (außer vielleicht bei sehr großen Apps: Es dauert 1/4 Stunden, um die App, die wir haben, sauber zu kompilieren, zumindest unter Windows). Und Details der Implementierung sind sowieso ausgeblendet, wir schauen uns normalerweise nur die API-Dokumentation an, d. die sichtbare Schnittstelle.
Für die Anekdote sah ich einige C ++ - Bibliotheken, die zu 99% in Headern implementiert waren (nur mit .cpp-Dateien, wo das System sie anforderte) und damit den Java-Stil imitiert (C # war zu der Zeit nicht da ...) / p>
Ich würde sagen, dass idealerweise alle Informationen an einem einzigen Ort leben sollten und über ein Modulsystem verfügen, das das unnötige Neukompilieren unnötiger Details verhindert und den Compiler in die Lage versetzt, die Informationen nur aus der Schnittstelle zu extrahieren (zB um mit einer Bibliothek oder was auch immer zu versenden).
Sie werden in C # und Java nicht wirklich benötigt, da Sie die Zugriffsebene für jede Methode (z. B. public oder private) angeben können und darüber hinaus Reflexionsvermögen haben, wie Sie es in C ++ nicht haben.
Beachten Sie, dass die Verwendung von Header-Dateien bei Nicht-OOP-Praxen nicht so schlimm ist. Sie können beispielsweise nur deklarieren, welche Funktionen den Clients in Ihren Header-Dateien öffentlich zugänglich sein sollen, während andere verborgen (und daher nicht zugänglich) bleiben, indem Sie sie nur in der .cpp- oder .c-Datei deklarieren.
Ich würde sagen, dass die meisten OO-Sprachen all die Kilometer, die sie in dieser Hinsicht benötigen, von Schnittstellen erhalten. Es bietet die ganze Flexibilität (d. H. Trennung der Schnittstelle von der Implementierung) von Headerdateien, während es strengere Verträge mit den Clients gibt, die die Schnittstellen verwenden (weil sie von der Sprache / dem Compiler erzwungen werden).
Kopfzeilen in C und C ++ sind für mich eine große Zeit- und Produktivitätssenke. Kompilieren ... hoppla, vergessen, die Signatur einer Methode zu reparieren. Kompilieren ... whoops, müssen Methode A zu Klasse X hinzufügen.
Um Header loszuwerden, muss die Ausgabe des Compilers die Beschreibung des Codes enthalten, die der Compiler selbst verstehen kann. Das war mit älteren Linkern nicht einfach: Die Objektdateien, die sie verwendeten, konnten nicht zu schlau sein. Daher wurde die Aufgabe, die Beschreibung des Codes zu erstellen, einem Menschen überlassen: der Header-Datei.
Die neueren Sprachen umgehen entweder den Linker (die interpretierten und die VM-Sprachen) oder verwenden benutzerdefinierte Linker (Turbo Pascal, ich nehme auch Delphi an). Aber selbst jetzt, wenn Sie mit Linker (oder seinem jüngeren Bruder, dynamischem Bibliothekslader) arbeiten, müssen Sie eine Art Beschreibung dessen erstellen, was sich in der Bibliothek befindet.
Die meisten anderen Sprachen sind nicht annähernd so stumpf und schwer zu analysieren und zu kompilieren wie C ++, daher ist die "Leistungsoptimierung" der Trennung von Header und Implementierung nicht so wichtig.
In C / C ++ Header-Dateien sind im Grunde eine Möglichkeit, Variablen zu gruppieren, die andernfalls in jeder Kompilierungseinheit, in der sie verwendet werden, als extern deklariert werden müssen.
Dies hat jedoch nicht die Komplexität oder Vielfalt von Problemdomänen begrenzt, mit denen C / C ++ umgehen kann. Es ist nur so, dass sich die Programmiersprache so entwickelt hat. Letztendlich kommt es darauf an, dass der Linker irgendwie alle Referenzen und Typen der Variablen ermittelt, die Sie in Ihrem Programm verwendet haben.
Die Art und Weise, wie C / C ++ dies tut, ist im Vergleich zu den neuen Programmiersprachen, die Unterstützung in der Muttersprache für die Verarbeitung von externen Referenzen auf Variablen und Methoden zu haben scheinen, ziemlich grob.