Warum haben Objekte derselben Klasse Zugriff auf die privaten Daten des jeweils anderen?

97

Warum haben Objekte derselben Klasse Zugriff auf die privaten Daten des jeweils anderen?

class TrivialClass {
public: 
  TrivialClass(const std::string& data) :
    mData(data) {};

  const std::string& getData(const TrivialClass& rhs) const {
    return rhs.mData;
  };

private:
  std::string mData;
};

int main() {
  TrivialClass a("fish");
  TrivialClass b("heads");

  std::cout << "b via a = " << a.getData(b) << std::endl;
  return 0;
}

Dieser Code funktioniert. Es ist durchaus möglich, dass Objekt a von Objekt b aus auf private Daten zugreift und diese zurückgibt. Warum sollte das so sein? Ich würde denken, dass private Daten privat sind. (Ich habe zunächst versucht, Kopierkonstruktoren in der Pimpl-Sprache zu verstehen, aber dann habe ich festgestellt, dass ich diese einfache Situation nicht einmal verstanden habe.)

Keith
quelle
18
Nun, als Ausgangspunkt könnten Sie keine Kopierkonstruktoren für etwas anderes als die einfachsten Klassen richtig implementieren. Sie können sich Klassen als ihren eigenen besten Freund vorstellen :-)
Cameron
4
Denken Sie privat von ihren Kunden, aber alle Mitarbeiter der Klasse haben Zugang
Martin Beckett
Danke Cameron. Das macht Sinn, aber warum ist dieser Zugriff dann nicht nur auf Kopierkonstruktoren und Zuweisungsoperatoren beschränkt?
Keith
5
Objekte des gleichen Typs interagieren oft viel. Und niemand zwingt Sie, eine Methode zu schreiben, die private Daten einer anderen Instanz verteilt. :)
OnkelBens
4
Einfach, weil der Compiler zur Kompilierungszeit keine Möglichkeit hat, dasselbe Objekt zu identifizieren. Das Erzwingen eines solchen Zugriffs würde Laufzeitunterstützung erfordern.
Chethan

Antworten:

79

Denn so funktioniert es in C ++. In C ++ funktioniert die Zugriffssteuerung auf Klassenbasis und nicht auf Objektbasis.

Die Zugriffssteuerung in C ++ ist als statische Funktion zur Kompilierungszeit implementiert. Ich denke, es ist ziemlich offensichtlich, dass es nicht wirklich möglich ist, eine sinnvolle Zugriffskontrolle pro Objekt zur Kompilierungszeit zu implementieren. Auf diese Weise kann nur die Steuerung pro Klasse implementiert werden.

Einige Hinweise zur objektbezogenen Steuerung sind in der Spezifikation für geschützten Zugriff enthalten , weshalb sie im Standard (11.5) sogar ein eigenes Kapitel enthält. Dennoch sind alle dort beschriebenen objektspezifischen Merkmale eher rudimentär. Auch hier soll die Zugriffssteuerung in C ++ auf Klassenbasis funktionieren.

Ameise
quelle
9
+1. C ++ ist sehr umfangreich in Bezug auf Mechanismen zur Kompilierungszeit, nicht so stark in Bezug auf Laufzeitmechanismen. Ziemlich gute allgemeine Regel.
Nemo
4
Ihr "Es ist nicht wirklich möglich, eine sinnvolle Zugriffskontrolle pro Objekt zur Kompilierungszeit zu implementieren". Warum nicht? In void X::f(X&x)ist der Compiler leicht zu unterscheiden this->aund x.a. Es ist (immer) nicht möglich, dass der Compiler das weiß *thisund xtatsächlich dasselbe Objekt x.f(x)ist, wenn er aufgerufen wird, aber ich könnte sehr gut sehen, dass ein Sprachdesigner dies in Ordnung findet.
André Caron
@ AndréCaron Ich denke, das ist tatsächlich ein viel größerer Fischkessel, als du es dir vorstellst. Wenn kein Inlining auftritt, muss der Compiler immer prüfen, ob thisund ob sie &xgleich sind. Um es noch schlimmer diese endet tatsächlich ein Problem ist auch mit X::f(Y& y), weil unser konkretes Objekt vom Typ sein könnte , Zdass erbt von beiden Xund Y. Kurz gesagt, es ist ein echtes Durcheinander, nicht performant, es ist schwierig, mit MI vernünftig zu arbeiten.
Nir Friedman
@NirFriedman Ich denke, Sie verstehen den Vorschlag falsch. Wenn beim Kompilieren X::f(X& x)Zugriffe auf vorhanden sind, x.awird es nicht kompiliert. Es ändert sich nichts anderes, es müssen keine Überprüfungen eingefügt werden, sodass die Leistung noch gültiger Programme nicht beeinträchtigt wird. Und es wird nicht als bahnbrechende Änderung an vorhandenem C ++ vorgeschlagen, sondern als etwas, das Designer bei der privateursprünglichen Einführung hätten tun können .
Alexey Romanov
31

"Privat" ist eigentlich kein Zugriffskontrollmechanismus im Sinne von "Ich habe meine Bilder auf Facebook privat gemacht, damit Sie sie nicht sehen können."

In C ++ sagt "privat" einfach, dass dies Teile einer Klasse sind, die Sie (der Codierer der Klasse) in zukünftigen Versionen usw. ändern könnten, und Sie möchten nicht, dass andere Codierer, die Ihre Klasse verwenden, sich auf ihre Existenz oder Funktionalität verlassen .

Wenn Sie eine echte Zugriffskontrolle wünschen, sollten Sie echte Datensicherheitstechniken implementieren.

vsekhar
quelle
13

Dies ist eine gute Frage, und ich bin kürzlich auf diese Frage gestoßen. Ich hatte einige Diskussionen mit meinen Kollegen und hier ist die Zusammenfassung unserer Diskussion: Dies ist beabsichtigt. Dies bedeutet nicht, dass dieses Design in allen Fällen völlig vernünftig ist, aber es muss einige Überlegungen geben, warum pro Klasse privat gewählt wird. Die möglichen Gründe, an die wir denken könnten, sind:

Erstens könnten die Kosten für die Zugriffskontrolle pro Instanz sehr hoch sein. Dies wurde von anderen in diesem Thread diskutiert. Theoretisch kann dies über diese Zeigerprüfung erfolgen. Dies kann jedoch nicht zur Kompilierungszeit und nur zur Laufzeit erfolgen. Sie müssen also die Zugriffskontrolle jedes Mitglieds zur Laufzeit identifizieren. Wenn diese verletzt wird, werden möglicherweise nur Ausnahmen ausgelöst. Die Kosten sind hoch.

Zweitens hat die Zugriffssteuerung pro Klasse einen eigenen Anwendungsfall, z. B. Kopierkonstruktor oder Operator =. Es wäre schwierig, sie zu implementieren, wenn die Zugriffskontrolle pro Instanz erfolgt.

Außerdem erfolgt die Zugriffssteuerung hauptsächlich aus Programmier- / Sprachperspektive, um den Zugriff auf den Code / das Mitglied und nicht auf die Daten zu modularisieren / zu steuern.

JackyZhu
quelle
12

Es ist eine willkürliche Entscheidung für das Sprachdesign. In Rubyprivate bedeutet dies beispielsweise wirklich privat, da in "nur die Instanz auf ihre eigenen privaten Datenelemente zugreifen kann". Dies ist jedoch etwas restriktiv.

Wie in den Kommentaren erwähnt, sind Kopierkonstruktoren und Zuweisungsoperatoren häufige Orte, an denen Sie direkt auf die privaten Datenelemente einer anderen Instanz zugreifen. Es gibt weniger offensichtliche Gründe dafür.

Betrachten Sie den folgenden Fall. Sie implementieren eine OO-verknüpfte Liste. Die verknüpfte Liste verfügt über eine verschachtelte Knotenklasse zum Verwalten von Zeigern. Sie können diese Knotenklasse so implementieren, dass sie die Zeiger selbst verwaltet (anstatt die Zeiger öffentlich zu haben und von der Liste verwaltet zu werden). In einem solchen Fall hätten Sie die Knotenobjekte, die die Zeiger anderer Knotenobjekte an anderen Stellen als dem typischen Kopierkonstruktor und Zuweisungsoperator ändern möchten.

André Caron
quelle
4

Der Trick besteht darin, sich daran zu erinnern, dass sich die Daten privateauf die Klasse und nicht auf die Instanz der Klasse beziehen. Jede Methode in Ihrer Klasse kann auf die privaten Daten einer beliebigen Instanz dieser Klasse zugreifen. Es gibt keine Möglichkeit, Daten innerhalb einer Instanz privat zu halten, es sei denn, Sie verbieten Methoden, die explizit auf private Datenelemente anderer Instanzen zugreifen.

Adam Maras
quelle
1

Berücksichtigen Sie zusätzlich zu allen oben genannten Antworten benutzerdefinierte Kopierkonstruktoren, Zuweisungsoperatoren und alle anderen Funktionen, die Sie für eine Klasse schreiben würden, die auf anderen Instanzen ausgeführt wird . Sie benötigen Accessor-Funktionen für alle diese Datenelemente.

Jacob
quelle
-8

Private Daten bleiben privat, bis jemand, der Zugriff darauf hat, sie anderen offenbart.

Dieses Konzept gilt auch für andere Situationen wie:

class cMyClass
{
public:
   // ...
   // omitted for clarity
   // ...

   void Withdraw(int iAmount)
   {
      iTheSecretVault -= iAmount;
   }

private:
   int iTheSecretVault;
};

Wie könnte jemand das Geld abheben? :) :)

YeenFei
quelle
3
In diesem Beispiel greift keine Klasseninstanz auf die privaten Datenelemente einer anderen Instanz zu.
André Caron
@Andre, "Dieses Konzept gilt auch für andere Situationen, wie ..."
YeenFei
^ "andere Situation" sind per Definition nicht zum Thema, daher ist Ihr Beispiel nicht relevant (und ich bin nicht sicher, ob es auch anderswo informativ wäre)
underscore_d
1
Dies ist überhaupt keine richtige Erklärung für die Frage.
Panda