2016-07-09 10 views
3

Ich bin auf eine interessante Theorie gestoßen und habe mich gefragt, ob es in C++ einen Sicherheitsmechanismus dagegen gibt.Vererbung und Freunde: Sicherheitsmechanismus?

All dies ist legal - Klasse C ist ein Freund der Basis und kann daher b.a() anrufen. Da es jedoch eine Referenz erhalten hat, kann es eine Referenz auf ein abgeleitetes Objekt erhalten, und somit würde C auf den privaten Bereich in der Klasse Abgeleitet zugreifen, ohne ein Freund von abgeleitet zu sein.

Ist das einfach ein schlechtes Code-Design oder gibt es einen sicheren Schutz davor? Passiert mir, wenn ich den Operator < < für die Basis außer Kraft setze und eine allgemeine Druckfunktion von innen aufruft (der Operator war ein Freund der Basis).

+1

In C++ haben Sie Freunde, so dass Sie an ihre privaten Teile gelangen können. – Mikhail

+0

Die Möglichkeit, dies zu visualisieren, besteht darin, dass die Zugriffsspezifizierer der abgeleiteten Klasse auf Zugriffe über lvalues ​​des statischen Typs und seiner Nachkommen angewendet werden, anstatt die Zugriffsspezifizierer, die ihre Basis für den Zugriff durch basal lvalues ​​deklariert hat, rückwirkend zu ändern am wenigsten schlecht, möglicherweise absurd. –

Antwort

1

Wie das Skelett des Designs (von Base und Derived) steht, ist dies ein typisches gutes Design, das von Herb Sutter 15 years ago befürwortet wurde - außer dass Freund Klasse C überflüssig ist, da es die öffentliche Funktion run aufrufen kann ().C muss nur dann ein Freund sein, wenn es nur a() benötigt, falls run() mehr Funktionalität vermeidet (und ich würde in einem solchen Fall ein schlechtes Design vermuten). Ich fragte mich, was falsch mit meinem Lesen war, denn im Gegensatz zu den vorherigen Antworten sehe ich nicht, dass a() öffentlich ist, noch sehe ich, dass Base eine private Basis ist. Genießen Sie

+0

Der Link in der Antwort bietet die genaue Erklärung - ich würde es jedem empfehlen, der daran interessiert ist –

4

Hier sind keine Sicherheitsmaßnahmen erforderlich. So funktioniert C++.

Durch Überschreiben einer virtuellen Funktion in der Basisklasse wird die abgeleitete Klasse neu implementiert. Die Definition der "Neuimplementierung" beinhaltet jedoch, dass das gesamte Gepäck aus der Basisklasse übernommen wird. Einschließlich der Tatsache, dass die virtuelle Funktion in der Basisklasse in diesem Fall public ist.

Die Tatsache, dass die abgeleitete Klasse die neu implementierte Funktion als private definiert, ändert nichts an der Tatsache, dass sie eine öffentliche Funktion überschreibt. Und als solches sollte es erwarten, dass es weiterhin über die Basisklasse erreichbar ist.

höchstens, ich nehme an, Sie können dies eine "Eigenart" nennen. Die Quintessenz ist, dass, wenn Sie eine virtuelle Funktion public überschreiben, der Prozess des Überschreibens die Tatsache nicht ändert, dass es eine öffentliche Funktion ist. Die übergeordnete Funktion "privat", in der abgeleiteten Klasse, schließt die Scheune, nachdem die Pferde bereits gegangen sind.

Und Sie müssen sich der Tatsache bewusst sein, dass Sie eine öffentliche virtuelle Funktion überschreiben. In einigen Situationen würde ich sagen, dass dies sogar ein Feature sein kann. Es wäre nicht allzu schwierig, sich eine Situation vorzustellen, in der eine bestimmte Basisklassenfunktion nur von dem vorhandenen Code aufgerufen werden sollte, der direkt auf die Basisklasse verweist. Jeder Code, der über einen Zeiger oder eine Referenz auf die abgeleitete Klasse verfügt, ist Code höherer Ebene, auf dem kein Unternehmen die Funktionen der Basisklasse aufrufen darf. Dies wäre natürlich eine Möglichkeit, dies zu tun. Dies ist sicherlich nicht als eine Art eiserne Sicherheit gedacht, sondern lediglich ein Mechanismus für den Compiler, der Ihnen hilft, logische oder funktionale Fehler zu finden oder Fehler zu konstruieren.

+0

Ich denke, eine einfachere Möglichkeit, dies zu visualisieren, ist, dass der Zugriffsspezifizierer der abgeleiteten Klasse auf Zugriffe über lvalues ​​des statischen Typs und seiner Nachkommen angewendet wird, anstatt rückwirkend die Spezifikationen seiner Basis zu ändern, was natürlich absurd wäre. –

+0

Und ... * (Achselzucken) * "Wofür sind 'Freunde'?" ... Ja, sie sind diejenigen, die dich von der Party nach Hause fahren und dann am nächsten Tag so tun, als wärst du nie betrunken gewesen. In C++ ist der Begriff "Freund": "jemand, dem wir vertrauen können", um mit einem Nicken und einem wissenden Zwinkern davonzukommen. Ein "Freund" ist ... sollen wir sagen ... ein bisschen ein * Landsmann. * Ein "manchmal-sehr-notwendiges Übel ..." –

+0

Ein 'Freund' einer C++ - Klasse ist informell etwas, was Klasse ist vertraut ausreichend, um uneingeschränkten Zugriff auf alle seine privaten, geschützten und öffentlichen Teile zu gewähren. Eine C++ - Klasse vertraut also allen ihren Freunden mehr als den Menschen. – Peter

4

Nun, nein, das ist nicht schlechtes Design von C++. Es ist ein schlechtes Design deines Programms.

Ein Programm, das etwas tut, wie

some_C.doSomething(some_derived); 

wird nicht kompilieren. Dies liegt daran, dass Ihre Base eine private Basis von Derived ist. Daher ist die Umwandlung von Derived & in Base & ungültig.

Die Ausnahme zu den oben genannten ist, wenn die aufrufende Funktion, die dies tut, entweder ein Mitglied oder friend von Derived ist. In diesem Fall wird das Verhalten vom (Entwickler von) Derived kontrolliert, wenn Sie so etwas getan haben, liegt es allein in Ihrer Verantwortung.