Ich möchte auf ein privates Datenelement in einer Klasse zugreifen. Es gibt keine Memberfunktion in der Klasse, um auf das private Datenelement zuzugreifen. Es ist privat.
Ich möchte die Klasse nehmen und einige, wie sie es öffnen. Eine Methode bestand darin, die Deklaration der Klasse zu kopieren, das private Member öffentlich zu machen und die neue Klassenklasse something_else aufzurufen. Dann mache ich eine Neuinterpretation und kopiere das Originalobjekt. Das funktioniert. Aber ich möchte etwas eleganteres ... oder vielleicht generisches ... oder nur einen anderen Weg.
Welche Möglichkeiten gibt es? Kann ich void * verwenden? Kann ich die Klasse in eine andere leere Klasse einbetten? Was sind Möglichkeiten, dies zu tun?
%
Ich gehe davon aus,
Es gibt einige Möglichkeiten, den Zugriff auf die privaten Mitglieder einer Klasse zu untergraben, wie in GotW # 76 demonstriert.
friend
-Deklaration hinzu. #define private public
, bevor du die Kopfzeile der Klasse einfügst . reinterpret_cast
, um von der ursprünglichen Klasse in eine falsche Klasse zu wechseln. Mit der Idee, die Sie in Ihrer Frage vorschlagen, müssen Sie das ursprüngliche Objekt nicht kopieren. Wenn Sie Ihre eigene "all public" -Variation der realen Klassendeklaration schreiben und dann einen Zeiger auf diesen neuen Typ setzen, können Sie direkt auf das Objekt zugreifen.
Der Grund, warum nichts davon eine gute Idee ist, ist einfach. Sie müssen Objekte einer Klasse bearbeiten, deren Quelle Sie nicht steuern (andernfalls könnten Sie die Quelle ändern, um Ihnen den benötigten Zugriff zu geben). Aber wenn Sie die Quelle nicht kontrollieren, was dann, wenn die Betreuer das Layout ihrer Klasse ändern? Ihre duplizierte Version stimmt nicht mehr überein, und der Compiler kann diesen Konflikt nicht erkennen. Das Ergebnis wird wahrscheinlich Speicherbeschädigung zur Laufzeit sein.
Da es falsch verstanden wird, muss ich klarstellen. Bei allen folgenden Lösungen müssen Sie das Objekt nicht erneut kompilieren . Um eine Klasse in Ihrem Code zu verwenden, sollten Sie, wenn sie in eine Objektdatei kompiliert ist, eine Header-Datei mit der Deklaration dieser Klasse einfügen.
%Vor%Es ist möglich (aber gefährlich, wenn Sie nicht vorsichtig sind), den Header (a) zu ändern oder den Header an einen anderen Ort zu kopieren und den Header (b), einzuschließen, ohne das neu zu kompilieren Klasse selbst .
%Vor% Ihr Code, in den Sie den neuen Header eingefügt haben, wird nur denken , dass er innerhalb der Objektdatei (die Sie nicht neu kompiliert haben!) die Implementierung der deklarierten Klasse in class_fixed.h
findet. Während dort die Klasse in class.h
deklariert bleibt. Wenn Sie Offsets von Mitgliedern (z. B. neue Mitglieder hinzufügen) in Ihrer neuen Kopfzeile ändern, sind Sie tot und der Code wird nicht ordnungsgemäß funktionieren. Aber nur den Zugriff zu ändern funktioniert gut. Kompilierter Code weiß nichts über den Zugriff, dies ist nur bei der Kompilation merkwürdig.
Das ist nicht immer schädlich. Im täglichen Leben begegnen Sie einer solchen Änderung, wenn Sie eine neue Version einer Bibliothek in Ihr System installieren und nicht alle Programme neu kompilieren, die davon abhängen. Aber es sollte mit Vorsicht behandelt werden
Es gibt mehrere Lösungen.
memcpy()
Nicht! Nicht memcpy als Objekt kopieren unterliegt manchmal bestimmten Richtlinien vom Klassendesigner auferlegt. Zum Beispiel kann auto_ptr
s nicht nur memcopied werden: Wenn Sie die auto_ptr
memcopy speichern, wird Destruktor ausgeführt Bei beiden versuchen Sie, denselben Speicher zweimal freizugeben, und das Programm stürzt ab.
Ändern von private:
in public:
im Header oder mit Makro
Wenn es Ihre Lizenz erlaubt, können Sie Ihr Problem lösen, indem Sie
Hinzufügen einer neuen Getterfunktion
Das Ändern von private
in public
ist fast immer in Ordnung (es sei denn, Sie verlassen sich auf bestimmte Kompilierzeitüberprüfungen, die die Kompilierung unterbrechen sollten, wenn die Klasse bestimmte Member verfügbar hat). das Hinzufügen neuer Getter-Funktion sollte sorgfältig durchgeführt werden. Die Getter-Funktion sollte inline sein (und daher in der Header-Datei der Klasse definiert sein).
reinterpret_cast
Die Umwandlung funktioniert gut, wenn Sie keinen Zeiger auf die dynamische Basisklasse darstellen (dynamisch bedeutet "mit virtuellen Funktionen oder Basen "), deren tatsächliche Instanz zum Zeitpunkt des Castings aus der Klasse am jeweiligen Codeelement abgeleitet werden kann.
protected:
Und nur für den Fall, dass Sie es vergessen haben. C ++ kann Mitglieder protected:
deklarieren, d.h. nur für die Klassen, die von dem gegebenen abgeleitet sind. Dies kann Ihre Bedürfnisse erfüllen.
Sie können, aber Sie sollten nicht. Die Objekte sind nur Speicher. Sie können den Zeiger sicherlich in eine äquivalente Klasse umwandeln, die die gleichen Mitglieder hat, aber alles öffentlich ist. Aber warum willst du das machen? Haben Sie den Code von jemand anderem, mit dem Sie arbeiten müssen? Lassen Sie sie die richtigen Zugriffsmethoden hinzufügen. Müssen Sie sie wirklich als öffentliche Mitglieder behandeln? Ändern Sie die Klasse.
Ich bin nicht wirklich sicher, was Sie versuchen, aber es ist wahrscheinlich ein Fehler.
Ich stimme dem Kommentar "Bearbeiten der Quelle" zu, aber ich denke, Sie sollten eine Methode hinzufügen und nicht nur die "private" auskommentieren.
Sie müssen die Deklaration der Klasse haben, also haben Sie vermutlich den Header, aber möglicherweise nicht die .cpp / was auch immer Datei. Fügen Sie der Klasse in einer Kopie des Headers eine Inline-Memberfunktion hinzu, und fügen Sie diesen Header anstelle des Originals ein. Sie sollten weiterhin in der Lage sein, eine Verknüpfung zur Objektdatei für den nicht zugänglichen Quellcode herzustellen.
Natürlich zählt dies als ein böser Hack, der die in die Sprache eingebauten Schutzmechanismen umgeht, anstatt mit ihnen zu arbeiten. Deshalb schlage ich den minimal bösen Hack vor - mach nicht alles privat, und wenn du mit einem Getter durchkommen kannst (aber kein Setter), tu das. Natürlich ist das wirkliche, minimale Übel nicht, es zu tun, wenn es irgendeinen Weg gibt, es zu vermeiden.
Denken Sie daran, wenn es sich um eine andere Klasse handelt, mit der Sie arbeiten, wird die nächste Version möglicherweise anders implementiert und hat möglicherweise dieses Mitglied überhaupt nicht.
Danke ... Ich wollte den Code für meine ursprüngliche Reparatur zeigen. Der Grund dafür ist, dass ich den Originalcode nicht ändern kann ... also muss ich eine Gefängnispause machen.
%Vor%Das funktioniert ... aber ich denke, ich möchte etwas generischeres ... oder flexibleres.
%