Sollte C ++ Header-Dateien entfernen? [geschlossen]

72

Viele Sprachen wie Java, C # trennen die Deklaration nicht von der Implementierung. C # hat ein Konzept der Teilklasse, aber Implementierung und Deklaration bleiben weiterhin in derselben Datei.

Warum hat C ++ nicht das gleiche Modell? Ist es praktischer, Header-Dateien zu haben?

Ich beziehe mich auf aktuelle und kommende Versionen des C ++ - Standards.

Sasha
quelle
13
Ich glaube, es gibt keinen wirklichen Grund für Header-Dateien in C ++. Alle darin gespeicherten Informationen werden in der .cpp dupliziert und können automatisch extrahiert werden (wie von www.lazycplusplus.com gezeigt - Haftungsausschluss: nicht verwendet). Das Problem ist die Kompilierungsgeschwindigkeit und C # & Java haben gezeigt, dass dies überwindbar ist.
2
Poste dies als Kommentar, da ich in meinen Informationen nicht sicher bin :) und ich bin mir nicht sicher, warum dies abgelehnt wird und zum Schließen. Es ist eine ausgezeichnete Frage IMO. ;)
1
Danke ... Ich habe keine Ahnung, warum es auch abgelehnt wurde
3
Brian: Was meinst du mit "einen leeren Zeiger reservieren"? Wie Sie wahrscheinlich wissen, müssen statisch zugewiesene Daten in C / C ++ manuell in der CPP definiert werden, nachdem sie im Header deklariert wurden (es sei denn, sie haben einen Dateibereich). Mit LazyC ++ überspringen Sie einfach die Header-Deklaration und schreiben die Implementierungsdefinition
3
Brian - siehe meine Antwort an Tim. In LazyC ++ Sie sind das Schreiben tatsächlich die Klassendefinition (einschließlich Polsterung Sie möchten), können Sie duplizieren nur die Dinge nicht. Übrigens, Ihre "Reservierung" ist ein nicht portierbarer Hack. Mit der Cheshire Cat-Sprache sind Sie besser dran.

Antworten:

23

Ich wechsle routinemäßig zwischen C # und C ++, und das Fehlen von Header-Dateien in C # ist einer meiner größten Probleme. Ich kann mir eine Header-Datei ansehen und alles lernen, was ich über eine Klasse wissen muss - wie ihre Mitgliedsfunktionen heißen, ihre aufrufende Syntax usw. -, ohne durch Seiten des Codes blättern zu müssen, der die Klasse implementiert.

Und ja, ich kenne Teilklassen und # Regionen, aber es ist nicht dasselbe. Teilklassen verschlimmern das Problem tatsächlich, da eine Klassendefinition auf mehrere Dateien verteilt ist. Was #regions angeht, scheinen sie nie so erweitert zu werden, wie ich es mir für das, was ich gerade mache, gewünscht habe. Daher muss ich Zeit damit verbringen, diese kleinen Pluspunkte zu erweitern, bis ich die richtige Ansicht habe.

Wenn Visual Studios Intellisense für C ++ besser funktionieren würde, hätte ich vielleicht keinen zwingenden Grund, so oft auf .h-Dateien zu verweisen, aber selbst in VS2008 kann C ++ 'Intellisense C # nicht berühren

Marc Bernier
quelle
146
Sie erledigen die Aufgabe der Maschine, die Dokumentation zu extrahieren und sie zu mögen . Wow ...
25
In Java / C # verwenden Sie Interfaces, um die API anzuzeigen. Dies ist eine VIEL bessere Möglichkeit, die API anzuzeigen als eine Header-Datei. Eine separate Klassendatei wird als Implementierung verwendet.
KitsuneYMG
12
JA, ABER ... ohne die Extrameile zu gehen, mischen C ++ - Header-Dateien Implementierungsdetails und öffentliche Aufträge.
Peterchen
20
Mal sehen, wie Sie die Header verwenden, um die Schnittstelle von std :: vector ... oder einer anderen std-Auflistungsklasse ... oder absolut alles, was sich in Boost befindet ... zu überprüfen. All diese sind für diesen Zweck völlig nutzlos.
Roman Starkov
18
Jede richtige IDE liefert Ihnen alle Informationen, die Sie über Klassen und Methoden benötigen. Da Sie VS2008 erwähnen, bietet die Verwendung des Objektbrowsers eine vollständige Dokumentation sowie ein einfaches Suchen und Durchsuchen. Was brauchst du mehr? Denken Sie, dass das Durchsuchen von Seiten mit Header-Dateien einfacher ist?
Tarik
79

Abwärtskompatibilität - Header-Dateien werden nicht entfernt, da dies die Abwärtskompatibilität beeinträchtigen würde.

Gavin Miller
quelle
33

Header-Dateien ermöglichen eine unabhängige Kompilierung. Sie müssen nicht auf die Implementierungsdateien zugreifen oder diese haben, um eine Datei zu kompilieren. Dies kann verteilte Builds vereinfachen.

Dadurch können SDKs auch etwas einfacher erstellt werden. Sie können nur die Header und einige Bibliotheken bereitstellen. Es gibt natürlich Möglichkeiten, die andere Sprachen verwenden.

Steve Rowe
quelle
13
Offensichtlich ist Leichtigkeit kein Grund für Header, da: (1) sie schwer zu pflegen sind, doppelter Code sind und (2) sie für ein SDK automatisch extrahiert werden können. Verteilte Builds sind vermutlich der richtige Punkt.
2
Sie können problemlos eine unabhängige Kompilierung ohne Header-Dateien durchführen.
Bill K
11
Ich würde argumentieren, dass C ++ - Header die Implementierung NICHT von der Schnittstelle trennen. Um eine echte Trennung zu erreichen, müssen Sie PIMPL oder eine solche Zusammenfassung verwenden.
KitsuneYMG
1
Obwohl Sie theoretisch Recht haben - wenn die Header-Dateien leicht sind und nur die Schnittstelle deklarieren -, sind Header-Dateien in der Praxis schwer und mit bedingten Kompilierungselementen beladen.
Randolpho
3
Header ermöglichen eine separate Kompilierung und SDKs auf eher primitive Weise, müssen diese Dinge jedoch nicht unterstützen - .NET und Java unterstützen beide ohne Verwendung von Headern.
Michael Burr
32

Sogar Bjarne Stroustrup hat Header-Dateien als Kludge bezeichnet.

Aber ohne ein Standard-Binärformat, das die erforderlichen Metadaten enthält (wie Java-Klassendateien oder .NET PE-Dateien), sehe ich keine Möglichkeit, die Funktion zu implementieren. Ein abgespeckter ELF oder eine a.out-Binärdatei enthält nicht viele Informationen, die Sie extrahieren müssten. Und ich glaube nicht, dass die Informationen jemals in Windows XCOFF-Dateien gespeichert werden.

Peter Mortensen
quelle
5
Ich würde Mr. Stroustrup ernster nehmen, wenn er die Header-Dateien erfunden hätte. Dann würde er seinen Fehler eingestehen, anstatt die Sprache schlecht zu reden, mit der er es sich zum Ziel gesetzt hatte, abwärtskompatibel zu bleiben. Es ist, als würde man sich für einen Tintenfisch entscheiden und sich dann darüber beschweren, wie viele Tentakeln man darauf setzen muss.
Chris Lutz
Ich würde Mr. Stroustrup ernster nehmen, wenn er einen Compiler schreiben könnte. Dann konnte er alle gewünschten Informationen in die Objektdateien einfügen, unabhängig von Format oder Stripping.
kmarsh
2
C ++ - Header sind hässlich. In gut geschriebenem C-Code sind Header großartig - private Implementierungsdetails in einer Quelldatei sind wirklich privat und werden niemandem zugänglich gemacht.
Kyoryu
3
Ich würde Mr. Stroustrup ernster nehmen, wenn er Header-Dateien losgeworden wäre .
Quark
25
@ Chris Lutz, Kmarsh, Quark. Sie sprechen (unglaublich ignorant) von einem Mann, der C ++ entwickelt hat, bevor die meisten von Ihnen geboren wurden.
10ToedSloth
17

C wurde erstellt, um das Schreiben eines Compilers zu vereinfachen. Es macht eine Menge Sachen, die auf diesem einen Prinzip basieren. Zeiger dienen nur dazu, das Schreiben eines Compilers zu vereinfachen, ebenso wie Header-Dateien. Viele der auf C ++ übertragenen Dinge basieren auf der Kompatibilität mit diesen Funktionen, die implementiert wurden, um das Schreiben des Compilers zu vereinfachen.

Eigentlich ist es eine gute Idee. Als C erstellt wurde, waren C und Unix eine Art Paar. C portierte Unix, Unix lief C. Auf diese Weise konnten sich C und Unix schnell von Plattform zu Plattform verbreiten, während ein auf Assembly basierendes Betriebssystem für die Portierung komplett neu geschrieben werden musste.

Das Konzept, eine Schnittstelle in einer Datei anzugeben und die Implementierung in einer anderen, ist überhaupt keine schlechte Idee, aber das sind keine C-Header-Dateien. Sie sind lediglich eine Möglichkeit, die Anzahl der Durchgänge zu beschränken, die ein Compiler durch Ihren Quellcode ausführen muss, und eine begrenzte Abstraktion des Vertrags zwischen Dateien zu ermöglichen, damit diese kommunizieren können.

Diese Elemente, Zeiger, Header-Dateien usw. bieten keinen wirklichen Vorteil gegenüber einem anderen System. Wenn Sie mehr Aufwand in den Compiler investieren, können Sie ein Referenzobjekt so einfach kompilieren wie einen Zeiger auf genau denselben Objektcode. Dies ist, was C ++ jetzt tut.

C ist eine großartige, einfache Sprache. Es hatte einen sehr begrenzten Funktionsumfang, und Sie konnten ohne großen Aufwand einen Compiler schreiben. Das Portieren ist im Allgemeinen trivial! Ich versuche nicht zu sagen, dass es eine schlechte Sprache ist oder so, es ist nur so, dass Cs Hauptziele bei seiner Erstellung möglicherweise Reste in der Sprache hinterlassen, die jetzt mehr oder weniger unnötig sind, aber aus Kompatibilitätsgründen beibehalten werden.


Es scheint, dass einige Leute nicht wirklich glauben, dass C für Port Unix geschrieben wurde, also hier: ( von )

Die erste Version von UNIX wurde in Assembler-Sprache geschrieben, aber Thompson wollte, dass sie in einer höheren Sprache geschrieben wird.

Thompson versuchte 1971 erstmals, Fortran auf dem PDP-7 einzusetzen, gab jedoch nach dem ersten Tag auf. Dann schrieb er eine sehr einfache Sprache, die er B nannte und die er auf dem PDP-7 in Gang brachte. Es hat funktioniert, aber es gab Probleme. Erstens, weil die Implementierung interpretiert wurde, war sie immer langsam. Zweitens waren die Grundbegriffe von B, die auf der wortorientierten BCPL basierten, für eine byteorientierte Maschine wie die neue PDP-11 einfach nicht richtig.

Ritchie benutzte den PDP-11, um B Typen hinzuzufügen, die für eine Weile NB für "New B" hießen, und begann dann, einen Compiler dafür zu schreiben. "Damit die erste Phase von C wirklich diese beiden Phasen in kurzer Folge waren, wurden zunächst einige Sprachänderungen von B vorgenommen, wobei die Typstruktur hinzugefügt wurde, ohne dass die Syntax zu stark geändert wurde, und der Compiler ausgeführt wurde", sagte Ritchie.

"Die zweite Phase war langsamer", sagte er über das Umschreiben von UNIX in C. Thompson, das im Sommer 1972 begann, aber zwei Probleme hatte: herauszufinden, wie die grundlegenden Co-Routinen ausgeführt werden, dh wie die Steuerung von einem Prozess auf einen umgeschaltet wird Ein weiterer; und die Schwierigkeit, die richtige Datenstruktur zu erhalten, da die ursprüngliche Version von C keine Strukturen hatte.

"Die Kombination der Dinge hat dazu geführt, dass Ken im Sommer aufgegeben hat", sagte Ritchie. "Im Laufe des Jahres habe ich Strukturen hinzugefügt und wahrscheinlich den Compiler-Code etwas besser gemacht - besseren Code - und so haben wir im nächsten Sommer die konzertierten Anstrengungen unternommen und tatsächlich das gesamte Betriebssystem in C wiederhergestellt."


Hier ist ein perfektes Beispiel dafür, was ich meine. Aus den Kommentaren:

Zeiger existieren nur, um das Schreiben eines Compilers zu vereinfachen? Nein. Zeiger existieren, weil sie die einfachste mögliche Abstraktion über die Idee der Indirektion sind. - Adam Rosenfield (vor einer Stunde)

Du hast recht. Um die Indirektion zu implementieren, sind Zeiger die einfachste zu implementierende Abstraktion. In keiner Weise sind sie so einfach zu verstehen oder zu verwenden. Arrays sind viel einfacher.

Das Problem? Um Arrays so effizient wie Zeiger zu implementieren, müssen Sie Ihrem Compiler so ziemlich einen RIESIGEN Codestapel hinzufügen.

Es gibt keinen Grund, warum sie C nicht ohne Zeiger entworfen haben könnten, aber mit Code wie diesem:

int i=0;
while(src[++i])
    dest[i]=src[i];

Es wird viel Aufwand (seitens der Compiler) erfordern, die expliziten i + src- und i + dest-Ergänzungen herauszufiltern und denselben Code zu erstellen, den dies ergeben würde:

while(*(dest++) = *(src++))
    ;

Das Herausrechnen dieser Variablen "i" nach der Tatsache ist HARD. Neue Compiler können das, aber damals war es einfach nicht möglich, und das Betriebssystem, das auf dieser beschissenen Hardware läuft, brauchte solche kleinen Optimierungen.

Jetzt benötigen nur noch wenige Systeme diese Art der Optimierung (ich arbeite auf einer der langsamsten Plattformen - Kabel-Set-Top-Boxen, und die meisten unserer Inhalte befinden sich in Java) und in den seltenen Fällen, in denen Sie sie benötigen, die neuen C-Compiler sollte klug genug sein, um diese Art der Konvertierung selbst durchzuführen.

Bill K.
quelle
5
Zeiger existieren nur, um das Schreiben eines Compilers zu vereinfachen? Nein. Zeiger existieren, weil sie die einfachste mögliche Abstraktion über die Idee der Indirektion sind.
Adam Rosenfield
2
Pascal wurde entwickelt, um das Schreiben eines Compilers zu vereinfachen. Mit einem einfachen handcodierten Parser für rekursiven Abstieg können Sie so ziemlich davonkommen. C ist komplizierter.
David Thornley
7
Wer sagt, dass das Schreiben eines C-Compilers einfach ist, hat noch nie einen C-Compiler geschrieben.
2
C war ein früher Versuch, die Assemblersprache in Betriebssystemen zu ersetzen. D & R wollte praktisch auf dem Silizium programmieren. Deshalb Zeiger und keine andere Abstraktion. Sie wollten einen klaren Weg, um genau das zu tun, was sie im Assembler tun würden.
David Thornley
2
Mein Punkt zu Pascal ist, dass K & R, wenn das Hauptziel des C-Designs eine einfache Implementierung gewesen wäre, viel besser hätte abschneiden können und wollen. Es war nicht so schwer zu tun.
David Thornley
17

In Design und Evolution von C ++ gibt Stroustrup einen weiteren Grund an ...

Dieselbe Header-Datei kann zwei oder mehr Implementierungsdateien enthalten, die von mehr als einem Programmierer gleichzeitig bearbeitet werden können, ohne dass ein Versionsverwaltungssystem erforderlich ist.

Dies mag heutzutage seltsam erscheinen, aber ich denke, es war ein wichtiges Problem, als C ++ erfunden wurde.

Abhay
quelle
1
Selbst mit einem Versionsverwaltungssystem vereinfacht das Arbeiten an separaten Dateien das Zusammenführen.
kmarsh
10
+1 für Dieselbe Header-Datei kann zwei oder mehr Implementierungsdateien enthalten . Das ist ein Glücksfall für eine tragbare Anwendung, ohne #ifdef-fu zu missbrauchen . (Verwenden Sie einfach ein Makefile, das das richtige myclass.oaus dem plattenformabhängigen myclass-win.cpp/ generiert myclass-linux.cpp, und die Außenseite kümmert sich nur darum myclass.h)
Steve Schnepp
Dies ist in der Tat seltsam und sollte heutzutage überhaupt nicht als Grund diskutiert werden. Es ist eine Geschichte.
Retif
Dies spricht jedoch nicht dafür, warum Header benötigt werden. Sie könnten immer noch an zwei Implementierungsdateien arbeiten, selbst wenn die Sprache keine Header-Dateien hätte.
Andrew Palmer
@ Andrew: Dies war ein ergänzender Punkt zur akzeptierten Antwort. Sie könnten eine separate Implementierung für dieselbe Schnittstelle haben, und Header mit Deklarationen wurden als eine gute Möglichkeit angesehen, während die Ingenieure gleichzeitig an der Realisierung (en) arbeiteten.
Abhay
14

Wenn Sie C ++ ohne Header-Dateien wollen, dann habe ich gute Nachrichten für Sie.

Es existiert bereits und heißt D ( http://www.digitalmars.com/d/index.html )

Technisch gesehen scheint D viel besser zu sein als C ++, aber es ist momentan nicht Mainstream genug für die Verwendung in vielen Anwendungen.

Jeroen Dirks
quelle
2
Der entscheidende Punkt bei D, unabhängig davon, ob Sie es verwenden oder nicht, ist, dass es die meisten Funktionen von C ++ bietet. Sie haben vielleicht argumentiert, dass C ++ Header-Dateien benötigt, weil Vorlagen sie benötigen oder weil Sie sie irgendwie benötigen, wenn es um effizienten Code geht. Beide werden durch Ds Existenz als falsch gezeigt.
Quark
C ++ ist eine Sprache auf Systemebene. D ist nicht.
Prof. Falken
Auch wenn es die Frage nicht beantwortet, war dieser Kommentar für mich sehr hilfreich.
Simon
8

Eines der Ziele von C ++ ist es, eine Obermenge von C zu sein, und es ist schwierig, dies zu tun, wenn es keine Header-Dateien unterstützen kann. Wenn Sie Header-Dateien herausschneiden möchten, können Sie auch CPP (den Vorprozessor, nicht Plus-Plus) ganz herausschneiden. Sowohl C # als auch Java spezifizieren keine Makro-Vorprozessoren mit ihren Standards (es sollte jedoch beachtet werden, dass sie in einigen Fällen auch mit diesen Sprachen verwendet werden können und sogar verwendet werden).

Da C ++ gerade entwickelt wird, benötigen Sie - genau wie in C - Prototypen, um kompilierten Code, der auf externe Funktionen und Klassen verweist, statisch zu überprüfen. Ohne Header-Dateien müssten Sie diese Klassendefinitionen und Funktionsdeklarationen eingeben, bevor Sie sie verwenden können. Damit C ++ keine Header-Dateien verwendet, müssen Sie eine Funktion in der Sprache hinzufügen, die etwa das Java- importSchlüsselwort unterstützt. Das wäre eine wichtige Ergänzung und Veränderung. Um Ihre Frage zu beantworten, ob es praktisch wäre: Ich denke nicht - überhaupt nicht.

Peter
quelle
8

Viele Menschen sind sich der Mängel von Header-Dateien bewusst, und es gibt Ideen, ein leistungsfähigeres Modulsystem in C ++ einzuführen. Vielleicht möchten Sie einen Blick auf Module in C ++ (Revision 5) von Daveed Vandevoorde werfen.

Piotr Dobrogost
quelle
1
Leider hat es nicht nach C ++ 0x geschafft und wurde auf eine zukünftige TR verschoben.
andref
2

Nun, C ++ an sich sollte Header-Dateien aus Gründen der Abwärtskompatibilität nicht entfernen. Ich denke jedoch, dass sie im Allgemeinen eine dumme Idee sind. Wenn Sie eine Closed-Source-Bibliothek verteilen möchten, können diese Informationen automatisch extrahiert werden. Wenn Sie verstehen möchten, wie eine Klasse ohne Blick auf die Implementierung verwendet wird, sind Dokumentationsgeneratoren genau das Richtige für sie, und sie leisten verdammt viel bessere Arbeit.

Dsimcha
quelle
2

Es ist sinnvoll, die Klassenschnittstelle in einer separaten Komponente zur Implementierungsdatei zu definieren.

Dies kann mit Schnittstellen geschehen, aber wenn Sie diesen Weg gehen, sagen Sie implizit, dass Klassen hinsichtlich der Trennung von Implementierung und Vertrag mangelhaft sind.

Modul 2 hatte die richtige Idee, Definitionsmodule und Implementierungsmodule. http://www.modula2.org/reference/modules.php

Die Antwort von Java / C # ist eine implizite Implementierung derselben (wenn auch objektorientiert).

Header-Dateien sind ein Problem, da Header-Dateien Implementierungsdetails ausdrücken (z. B. private Variablen).

Bei der Umstellung auf Java und C # stelle ich fest, dass, wenn eine Sprache IDE-Unterstützung für die Entwicklung erfordert (z. B. dass öffentliche Klassenschnittstellen in Klassenbrowsern navigierbar sind), dies möglicherweise eine Aussage ist, dass der Code nicht für sich allein steht besonders lesbar sein.

Ich finde die Mischung aus Schnittstelle und Implementierungsdetails ziemlich schrecklich.

Entscheidend ist, dass die fehlende Fähigkeit, die Signatur der öffentlichen Klasse unabhängig von der Implementierung in einer präzisen, gut kommentierten Datei zu dokumentieren, darauf hinweist, dass das Sprachdesign aus Gründen der Autorenschaft und der Wartung geschrieben wurde. Nun, ich streife jetzt über Java und C #.

mehrsprachig
quelle
2

Wenn Sie den Grund wollen, warum dies niemals passieren wird: Es würde so ziemlich die gesamte vorhandene C ++ - Software beschädigen. Wenn Sie sich einige der C ++ - Komiteedesign-Dokumentationen ansehen, haben sie verschiedene Alternativen untersucht, um zu sehen, wie viel Code es brechen würde.

Es wäre viel einfacher, die switch-Anweisung in etwas halbwegs Intelligentes zu ändern. Das würde nur einen kleinen Code brechen. Es wird immer noch nicht passieren.

BEARBEITET FÜR NEUE IDEE:

Der Unterschied zwischen C ++ und Java, der C ++ - Headerdateien erforderlich macht, besteht darin, dass C ++ - Objekte nicht unbedingt Zeiger sind. In Java werden alle Klasseninstanzen mit einem Zeiger referenziert, obwohl dies nicht so aussieht. In C ++ sind Objekte auf dem Heap und dem Stapel zugeordnet. Dies bedeutet, dass C ++ wissen muss, wie groß ein Objekt sein wird und wo sich die Datenelemente im Speicher befinden.

David Thornley
quelle
C ++, das eine Möglichkeit benötigt, das Klassenlayout im Speicher zu kennen, bedeutet nicht, dass es unbedingt Header-Dateien benötigt. Header-Dateien sind der aktuelle Mechanismus, mit dem C ++ diese Informationen abruft, nicht der einzig mögliche Mechanismus.
andref
2

Ein Vorteil dieser Trennung besteht darin, dass nur die Benutzeroberfläche angezeigt werden kann, ohne dass ein erweiterter Editor erforderlich ist .

Dimitri C.
quelle
1

Ohne Header-Dateien existiert keine Sprache. Es ist ein Mythos.

Schauen Sie sich eine proprietäre Bibliotheksdistribution für Java an (ich habe keine nennenswerte C # -Erfahrung, aber ich würde erwarten, dass es dieselbe ist). Sie geben Ihnen nicht die vollständige Quelldatei; Sie geben Ihnen nur eine Datei, in der die Implementierung jeder Methode ausgeblendet ist ( {}oder {return null;}ähnliches) und alles, was sie mit verstecktem Versteck davonkommen können. Sie können das nur als Header bezeichnen.

Es gibt jedoch keinen technischen Grund, warum ein C- oder C ++ - Compiler alles in einer entsprechend gekennzeichneten Datei zählen könnte, es externsei denn, diese Datei wird direkt kompiliert. Die Kosten für die Kompilierung wären jedoch immens, da weder C noch C ++ schnell analysiert werden können, und das ist eine sehr wichtige Überlegung. Bei jeder komplexeren Methode zum Verschmelzen von Headern und Quellen treten schnell technische Probleme auf, z. B. die Notwendigkeit, dass der Compiler das Layout eines Objekts kennt.

coppro
quelle
Der Java-Compiler extrahiert diese Informationen aus den .class-Dateien. Nicht nur das: Das Sun JDK wurde mit dem Quellcode für die meisten Klassen geliefert (außer für die in com.sun. *).
andref
@andref stimmen zu, die meisten modernen Sprachen (die normalerweise dynamische Sprachen sind) kommen nicht mit einer formalen Header-Datei
Tomsoft
1

Header-Dateien sind ein wesentlicher Bestandteil der Sprache. Ohne Header-Dateien werden alle statischen Bibliotheken, dynamischen Bibliotheken und so ziemlich jede vorkompilierte Bibliothek unbrauchbar. Header-Dateien erleichtern auch die Dokumentation aller Elemente und ermöglichen das Durchsuchen der API einer Bibliothek / Datei, ohne jedes einzelne Codebit zu durchlaufen.

Sie erleichtern auch die Organisation Ihres Programms. Ja, Sie müssen ständig von der Quelle zum Header wechseln, aber Sie können damit auch interne und private APIs innerhalb der Implementierungen definieren. Zum Beispiel:

MySource.h:

extern int my_library_entry_point(int api_to_use, ...);

MySource.c:

int private_function_that_CANNOT_be_public();

int my_library_entry_point(int api_to_use, ...){
  // [...] Do stuff
}

int private_function_that_CANNOT_be_public() {

}

Wenn Sie #include <MySource.h>, dann bekommen Sie my_library_entry_point.

Wenn Sie #include <MySource.c>, dann sind Sie auch bekommen private_function_that_CANNOT_be_public.

Sie sehen, wie schlecht das sein kann, wenn Sie eine Funktion zum Abrufen einer Liste von Kennwörtern oder eine Funktion zum Implementieren Ihres Verschlüsselungsalgorithmus oder eine Funktion zum Freilegen der Interna eines Betriebssystems oder eine Funktion zum Überschreiben von Berechtigungen haben. etc.

Élektra
quelle
-1

Oh ja!

Nach dem Codieren in Java und C # ist es wirklich ärgerlich, 2 Dateien für jede Klasse zu haben. Also habe ich mir überlegt, wie ich sie zusammenführen kann, ohne den vorhandenen Code zu beschädigen.

In der Tat ist es wirklich einfach. Fügen Sie einfach die Definition (Implementierung) in einen Abschnitt #ifdef ein und fügen Sie in der Compiler-Befehlszeile eine Definition hinzu, um diese Datei zu kompilieren. Das ist es.

Hier ist ein Beispiel:

/* File ClassA.cpp */

#ifndef _ClassA_
#define _ClassA_

#include "ClassB.cpp"
#include "InterfaceC.cpp"

class ClassA : public InterfaceC
{
public:
    ClassA(void);
    virtual ~ClassA(void);

    virtual void methodC();

private:
    ClassB b;
};

#endif

#ifdef compiling_ClassA

ClassA::ClassA(void)
{
}

ClassA::~ClassA(void)
{
}

void ClassA::methodC()
{
}

#endif

Kompilieren Sie diese Datei in der Befehlszeile mit

-D compiling_ClassA

Die anderen Dateien, die ClassA enthalten müssen, können dies nur

#include "ClassA.cpp"

Natürlich kann das Hinzufügen der Definition in der Befehlszeile einfach mit einer Makroerweiterung (Visual Studio-Compiler) oder mit automatischen Variablen (gnu make) und unter Verwendung derselben Nomenklatur für den Definitionsnamen hinzugefügt werden.

Vincent
quelle
2
Dadurch wird der Punkt der Trennung von Header und Quelldatei (fast) völlig verfehlt. Wenn Sie dies tun, müssen alle Benutzer von ClassA.cpp bei Änderungen an der Implementierung von ClassA neu kompiliert werden (es sei denn, Ihr Build-System ist wirklich intelligent, was an sich Kosten verursacht).
Mankarse
@Mankarse Wenn Sie Schnittstellen zwischen Klassen verwenden (wie in Java oder C #), hat das Ändern der Implementierung einer Klasse nur geringe Auswirkungen auf die Kompilierungsabhängigkeit.
Vincent
-3

Trotzdem verstehe ich einige Aussagen nicht. Die Trennung von API und Implementierung ist eine sehr gute Sache, aber Header-Dateien sind keine API. Dort gibt es private Felder. Wenn Sie ein privates Feld hinzufügen oder entfernen, ändern Sie die Implementierung und nicht die API.

qax
quelle