Warum werden private Variablen in der öffentlich zugänglichen Header-Datei beschrieben?

11

OK, hoffentlich ist dies eine subjektive Frage für Programmierer, aber hier geht es weiter. Ich erweitere ständig meine Kenntnisse in Sprachen und Software-Engineering-Praktiken ... und bin auf etwas gestoßen, das für mich überhaupt keinen Sinn ergibt.

In C ++ enthalten Klassendeklarationen private:Methoden und Parameter in der Header-Datei, die Sie theoretisch an den Benutzer übergeben, um sie einzuschließen, wenn Sie sie zu einer Bibliothek machen.

In Objective-C machen @interfaces fast dasselbe und zwingen Sie dazu, Ihre privaten Mitglieder aufzulisten (zumindest gibt es eine Möglichkeit, private Methoden in die Implementierungsdatei aufzunehmen).

Nach allem, was ich sagen kann, können Sie mit Java und C # eine Schnittstelle / ein Protokoll bereitstellen, die alle öffentlich zugänglichen Eigenschaften / Methoden deklarieren und dem Codierer die Möglichkeit geben, alle Implementierungsdetails in der Implementierungsdatei auszublenden .

Warum? Die Kapselung ist eines der Hauptprinzipien von OOP. Warum fehlt C ++ und Obj-C diese grundlegende Fähigkeit? Gibt es eine Art Best-Practice-Workaround für Obj-C oder C ++, die die gesamte Implementierung verbirgt ?

Vielen Dank,

Stephen Furlani
quelle
4
Ich fühle deinen Schmerz. Ich bin schreiend von C ++ weggelaufen, als ich einer Klasse zum ersten Mal ein privates Feld hinzugefügt habe und alles neu kompilieren musste, was es verwendet hat.
Larry Coleman
@ Larry, es macht mir nicht allzu viel aus, aber es scheint als eine großartige OO-Sprache angekündigt zu werden, aber es kann nicht einmal "richtig" kapseln.
Stephen Furlani
2
Glaube dem Hype nicht. Es gibt bessere Möglichkeiten, OO durchzuführen, sowohl in den statischen als auch in den dynamischen Schreibcamps.
Larry Coleman
Es ist in gewisser Hinsicht eine großartige Sprache, aber nicht wegen ihrer OO-Fähigkeiten, die eine Pfropfung von Simula 67 auf C.
David Thornley
Sie sollten etwas C-Programmierung machen. Dann haben Sie ein besseres Verständnis dafür, warum diese Sprachen so sind, wie sie sind, einschließlich Java C # usw.
Henry

Antworten:

6

Die Frage ist, ob der Compiler wissen muss, wie groß ein Objekt ist. Wenn ja, muss der Compiler die privaten Mitglieder kennen, um sie hochzählen zu können.

In Java gibt es primitive Typen und Objekte, und alle Objekte werden separat zugewiesen, und die Variablen, die sie enthalten, sind wirklich Zeiger. Da ein Zeiger ein Objekt mit fester Größe ist, weiß der Compiler daher, wie groß eine Variable ist, ohne die tatsächliche Größe des Objekts zu kennen, auf das verwiesen wird. Der Konstruktor erledigt das alles.

In C ++ können Objekte lokal oder auf dem Heap dargestellt werden. Daher muss der Compiler wissen, wie groß ein Objekt ist, damit er eine lokale Variable oder ein Array zuordnen kann.

Manchmal ist es wünschenswert, die Klassenfunktionalität in eine öffentliche und eine private Schnittstelle zu unterteilen, und hier kommt die PIMPL-Technik (Pointer to IMPLementation) ins Spiel. Die Klasse verfügt über einen Zeiger auf eine private Implementierungsklasse, und die Methoden der öffentlichen Klasse können sie aufrufen Das.

David Thornley
quelle
Kann der Compiler nicht in die Objektbibliothek schauen, um diese Informationen zu erhalten? Warum können diese Informationen nicht maschinenlesbar statt von Menschen lesbar sein?
Stephen Furlani
@Stephen: Zum Zeitpunkt der Kompilierung gibt es nicht unbedingt eine Objektbibliothek. Da sich die Größe der Objekte auf den kompilierten Code auswirkt, muss er zur Kompilierungszeit bekannt sein, nicht nur zur Verknüpfungszeit. Ferner ist es Ah möglich, Klasse A zu definieren, Bh Klasse B zu definieren und die Funktionsdefinitionen in A.cpp Objekte der Klasse B zu verwenden und umgekehrt. In diesem Fall wäre es notwendig, A.cpp und B.cpp voreinander zu kompilieren, wenn die Objektgröße aus dem Objektcode übernommen wird.
David Thornley
Kann während der Kompilierung keine Verknüpfung hergestellt werden? Ich gebe zu, dass ich Details in dieser Tiefe nicht kenne, aber wenn die Benutzeroberfläche eines Objekts dessen Inhalt verfügbar macht, können dieselben Inhalte nicht aus einer Bibliothek oder einer anderen maschinenlesbaren Komponente verfügbar gemacht werden? Müssen sie in einer öffentlich zugänglichen Header-Datei definiert werden? Ich verstehe , dieser Teil der Mehrheit der C Sprachen ist, aber ist es muß so sein?
Stephen Furlani
1
@Stephen: Die Verknüpfung kann nur während der Kompilierung erfolgen, wenn alle entsprechenden Komponenten vorhanden sind. Selbst dann wäre es ein komplizierter Prozess, der eine teilweise Kompilierung (alles außer den Objektgrößen), eine teilweise Verknüpfung (um die Objektgrößen zu erhalten), dann eine endgültige Kompilierung und Verknüpfung umfasst. Da C und C ++ relativ alte Sprachen sind, würde das einfach nicht passieren. Vermutlich könnte jemand eine neue Sprache ohne Header-Dateien entwerfen, aber es wäre nicht C ++.
David Thornley
14

Aufgrund des Designs von C ++ muss der Compiler wissen, wie groß das Objekt ist, um ein Objekt auf dem Stapel zu erstellen. Dazu müssen alle Felder in der Header-Datei vorhanden sein, da dies alles ist, was der Compiler sehen kann, wenn der Header enthalten ist.

Zum Beispiel, wenn Sie eine Klasse definieren

class Foo {
    public int a;
    private int b;
};

dann sizeof(Foo)ist sizeof(a) + sizeof(b). Wenn es einen Mechanismus zum Trennen der privaten Felder gab, könnte der Header enthalten

class Foo {
    public int a;
};

mit sizeof(Foo) = sizeof(a) + ???.

Wenn Sie private Daten wirklich verbergen möchten, versuchen Sie es mit der Pimpl-Sprache mit

class FooImpl;
class Foo {
    private FooImpl* impl;
}

im Header und eine Definition FooImplnur für Foodie Implementierungsdatei in.

Scott Wales
quelle
Oh. Ich hatte keine Ahnung, dass dies der Fall war. Haben Sprachen wie Java, C # und Obj-C deshalb "Klassenobjekte", damit sie die Klasse fragen können, wie groß das Objekt sein soll?
Stephen Furlani
4
Versuchen Sie es mit einem Pimpl, einem Zeiger auf eine private Implementierung. Da alle Klassenzeiger dieselbe Größe haben, müssen Sie die Implementierungsklasse nicht definieren, sondern nur deklarieren.
Scott Wales
Ich denke, das sollte eine Antwort statt eines Kommentars sein.
Larry Coleman
1

Dies alles hängt von der Wahl des Designs ab.

Wenn Sie die privaten Implementierungsdetails der C ++ - oder Objective-C-Klasse wirklich ausblenden möchten, stellen Sie entweder eine oder mehrere von der Klasse unterstützte Schnittstellen bereit (reine virtuelle C ++ - Klasse, Objective-C @protocol) und / oder Sie erstellen die Klasse Sie können sich selbst konstruieren, indem Sie eine statische Factory-Methode oder ein Class Factory-Objekt bereitstellen.

Der Grund dafür, dass die privaten Variablen in der Header-Datei / Klassendeklaration / @ -Schnittstelle verfügbar gemacht werden, besteht darin, dass ein Verbraucher Ihrer Klasse möglicherweise eine neue Instanz davon erstellen muss und ein new MyClass()oder [[MyClass alloc]init]im Client-Code den Compiler benötigt, um zu verstehen, wie groß eine MyClass ist Objekt ist, um die Zuordnung zu tun.

Java und C # haben auch ihre privaten Variablen in der Klasse detailliert - sie sind keine Ausnahme, aber IMO ist das Schnittstellenparadigma bei diesen Sprachen viel häufiger. Möglicherweise verfügen Sie nicht in jedem Fall über den Quellcode, aber der kompilierte / Byte-Code enthält genügend Metadaten, um diese Informationen abzuleiten. Da C ++ und Objective-C diese Metadaten nicht haben, sind die einzigen Details die tatsächlichen Details der Klasse / @ -Schnittstelle. In der C ++ COM-Welt machen Sie die privaten Variablen keiner Klasse verfügbar, können jedoch die Header-Datei bereitstellen, da die Klasse rein virtuell ist. Ein Klassenfactory-Objekt wird registriert, um auch die tatsächlichen Instanzen zu erstellen, und es gibt einige Metadaten in verschiedenen Formen.

In C ++ und Objective-C ist das Verteilen der Header-Datei weniger aufwendig als das Schreiben und Verwalten einer zusätzlichen Schnittstelle / @ -Protokolldatei. Dies ist ein Grund, warum Sie die private Implementierung so oft sehen.

Ein weiterer Grund in C ++ sind Vorlagen. Der Compiler muss die Details der Klasse kennen, um eine Version dieser Klasse zu generieren, die auf die angegebenen Parameter spezialisiert ist. Die Größe der Mitglieder der Klasse hängt von der Parametrisierung ab, daher müssen diese Informationen vorhanden sein.

JBRWilkinson
quelle