Warum müssen wir private Mitglieder in Überschriften setzen?

62

Private Variablen sind eine Möglichkeit, die Komplexität und Implementierungsdetails für den Benutzer einer Klasse zu verbergen. Dies ist ein ziemlich schönes Feature. Aber ich verstehe nicht, warum wir sie in c ++ in den Header einer Klasse schreiben müssen. Ich sehe zwei ärgerliche Nachteile:

  • Der Header des Benutzers wird unübersichtlich
  • Es erzwingt eine Neukompilierung aller Client-Bibliotheken, wenn die Interna geändert werden

Gibt es einen konzeptionellen Grund für diese Anforderung? Ist es nur, um dem Compiler die Arbeit zu erleichtern?

Simon Bergot
quelle
Sie können eine leere Struktur im Header deklarieren, aber dann dürfen Sie nur Zeiger auf eine solche Struktur verwenden, wenn Sie sie verwenden (und Sie können keine zuweisen)
Ratschenfreak
3
@ratchetfreak: Nein, empty ( struct foo{};) ist nicht erlaubt, forward declarations ( struct foo;) jedoch.
MSalters
@MSalters das habe ich gemeint
Ratschenfreak
1
Lassen Sie mich einen Nachteil hinzufügen: * Das Schreiben von Kopfzeilen für private Funktionen in die .h-Datei ist eine enorme Zeitverschwendung. (für einen Moment den Freundesunterricht vergessen)
Jonny

Antworten:

68

Dies liegt daran, dass der C ++ - Compiler die tatsächliche Größe der Klasse kennen muss, um bei der Instanziierung die richtige Speichermenge zuzuweisen. Und die Größe umfasst alle Mitglieder, auch private.

Eine Möglichkeit, dies zu vermeiden, ist die Verwendung des Pimpl-Idioms , das Herb Sutter in seinen Guru of the Week-Serien Nr. 24 und Nr. 28 erklärt hat .

Aktualisieren

Tatsächlich ist dies (oder allgemeiner die Unterscheidung zwischen Header- und Quelldatei und #includes) eine große Hürde in C ++, die von C geerbt wurde. In den Tagen, in denen C ++ C erstellt wurde, gab es noch keine Erfahrung mit umfangreicher Softwareentwicklung, in denen dies der Fall war fängt an, echte Probleme zu verursachen. Die Lektionen, die seitdem gelernt wurden, wurden von Designern neuerer Sprachen beachtet, aber C ++ ist an Abwärtskompatibilitätsanforderungen gebunden, was es wirklich schwierig macht, ein derart grundlegendes Problem in der Sprache anzugehen.

Péter Török
quelle
Sind solche Informationen nicht nur in der Klassenbibliothek enthalten? Wird es zum Verlinken verwendet?
Simon Bergot
@ Simon, was meinst du mit "Klassenbibliothek"?
Péter Török
Ich meine die Sammlung von Objektdateien mit der Klassendefinition und Methoden
Simon Bergot
7
Als C ++ erstellt wurde, hatte AT & T / Bell Labs (damals Stroustrups-Arbeitgeber) sicherlich Erfahrung mit der Entwicklung von C in großem Maßstab. Ihre 5ESS-Telefonvermittlungssoftware war zu der Zeit wahrscheinlich das größte einzelne C-Programm der Welt. Frühe Ideen zu OO sind bereits in dieser Codebasis sichtbar, und Cfront ahmte diese Techniken nach. Der Begriff privateist jedoch moderner.
MSalters
1
In C würden Sie den Allokator einfach in eine Bibliotheksfunktion einfügen. Der Kunde würde eine solche Struktur überhaupt nicht zuordnen können. Dies erhöht den Overhead ein wenig, macht aber das Migrieren des Codes über Versionen hinweg trivial, sodass es sich oft lohnt. Es führt jedoch tendenziell zu einem Codestil, der sich stark von dem in C ++ unterscheidet.
Donal Fellows
15

Die Klassendefinition muss ausreichen, damit der Compiler überall dort, wo Sie ein Objekt der Klasse verwendet haben, ein identisches Layout im Speicher erzeugt. Zum Beispiel mit etwas wie:

class X { 
    int a;
public:
    int b;
};

Der Compiler hat normalerweise den aOffset 0 und den bOffset 4. Wenn der Compiler dies als einfach ansah:

class X { 
public:
    int b;
};

Es würde "denken", dass bder Offset 0 anstelle von Offset 4 sein sollte. Wenn Code, der diese zugewiesene bDefinition verwendet a, geändert wird, wird Code, der die erste Definition verwendet , geändert und umgekehrt.

Der übliche Weg, um die Auswirkungen von Änderungen an den privaten Teilen der Klasse zu minimieren, wird normalerweise als Pimpl-Idiom bezeichnet (über das Google sicher viele Informationen geben kann).

Jerry Sarg
quelle
1
Ich frage nach einer Designentscheidung. Natürlich müssten Sie die Erklärung für private Mitglieder irgendwo ablegen, damit die Sprache funktioniert. Aber warum sollte es in der Kopfzeile stehen und nicht an einem privateren Ort?
Simon Bergot
7
@ Simon: Der Header ist alles, was der Compiler sieht, um zu sagen, wie die Klasse / Struktur aussieht. Es gab Diskussionen darüber, etwas wie Module zu C ++ hinzuzufügen, die diese Art von Daten ein bisschen mehr verbergen würden, aber bisher wurde es nicht genehmigt (obwohl es auch nicht vollständig gelöscht wurde).
Jerry Coffin
3
Eine triviale Regel wäre jedoch, solche ".cpp-defined" privaten Mitglieder zuletzt zuzuweisen. Dies bedeutet, dass der Versatz von öffentlichen und "normalen" privaten Mitgliedern nicht von ihnen abhängt. IMO ist der wahre Grund, dass Sie nicht von einer solchen Klasse erben können, da der abgeleitete Teil sogar diesen privaten Mitgliedern folgen muss.
MSalters
3

Es gibt höchstwahrscheinlich mehrere Gründe. Auf private Mitglieder können die meisten anderen Klassen nicht zugreifen, auf sie können jedoch weiterhin Freundesklassen zugreifen. Zumindest in diesem Fall werden sie möglicherweise in der Kopfzeile benötigt, damit die Friend-Klasse sehen kann, dass sie existieren.

Die Neukompilierung abhängiger Dateien hängt möglicherweise von Ihrer Include-Struktur ab. Das Einschließen der .h-Dateien in eine .cpp-Datei anstelle eines anderen Headers kann in einigen Fällen lange Ketten von Neukompilierungen verhindern.

thorsten müller
quelle