Dlaczego obiekty tej samej klasy mają dostęp do swoich prywatnych danych?
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;
}
Ten kod działa. Obiekt a może uzyskać dostęp do prywatnych danych z obiektu b i je zwrócić. Dlaczego tak się dzieje? Myślę, że prywatne dane są prywatne. (Zacząłem od zrozumienia konstruktorów kopiujących w idiomie pimpl, ale potem odkryłem, że nawet nie rozumiem tej prostej sytuacji).
c++
private-members
Keith
źródło
źródło
Odpowiedzi:
Ponieważ tak to działa w C ++. W C ++ kontrola dostępu działa na podstawie klasy , a nie obiektu.
Kontrola dostępu w C ++ jest implementowana jako statyczna funkcja czasu kompilacji. Myślę, że jest raczej oczywiste, że nie jest naprawdę możliwe zaimplementowanie jakiejkolwiek znaczącej kontroli dostępu dla poszczególnych obiektów w czasie kompilacji. W ten sposób można zaimplementować tylko kontrolę dla klasy.
Pewne wskazówki dotyczące kontroli poszczególnych obiektów są obecne w specyfikacji chronionego dostępu , dlatego też ma ona nawet własny, dedykowany rozdział w standardzie (11.5). Ale nadal wszelkie opisane cechy dla poszczególnych obiektów są raczej podstawowe. Ponownie, kontrola dostępu w C ++ ma działać na podstawie klasy.
źródło
void X::f(X&x)
programie kompilator jest w stanie łatwo odróżnićthis->a
ix.a
. To nie jest (zawsze) możliwe kompilator wiedział, że*this
ix
są w rzeczywistości ten sam przedmiot, jeślix.f(x)
jest wywoływany, ale mogę bardzo dobrze zobaczyć projektant język odnaleźć tę OK.this
i&x
są takie same. Co gorsza, w rzeczywistości kończy się to problememX::f(Y& y)
, ponieważ nasz konkretny obiekt może być typu,Z
który dziedziczy zarówno z, jakX
iY
. Krótko mówiąc, to prawdziwy bałagan, a nie wydajność, ciężko jest rozsądnie pracować z MI.X::f(X& x)
, jeśli są dostęp dox.a
, nie będzie się kompilować. Nic więcej się nie zmienia, nie trzeba wstawiać żadnych sprawdzeń, więc nie ma to wpływu na działanie nadal działających programów. I nie jest to sugerowane jako przełomowa zmiana w istniejącym C ++, ale jako coś, co projektanci mogliby zrobić, wprowadzającprivate
pierwotnie.„Prywatne” nie jest tak naprawdę mechanizmem kontroli dostępu w sensie „Zrobiłem moje zdjęcia na Facebooku jako prywatne, więc nie możesz ich zobaczyć”.
W C ++ „private” mówi po prostu, że są to części klasy, które Ty (programista tej klasy) możesz zmienić w przyszłych wersjach itp. I nie chcesz, aby inni programiści używający Twojej klasy polegali na ich istnieniu lub funkcjonalności .
Jeśli chcesz mieć prawdziwą kontrolę dostępu, powinieneś wdrożyć oryginalne techniki bezpieczeństwa danych.
źródło
To dobre pytanie i ostatnio zetknąłem się z tym pytaniem. Odbyłem kilka dyskusji z moimi kolegami i oto podsumowanie naszej dyskusji: To jest zgodne z projektem. Nie oznacza to, że ten projekt jest całkowicie rozsądny we wszystkich przypadkach, ale należy wziąć pod uwagę, dlaczego wybrana jest klasa prywatna. Możliwe powody, o których moglibyśmy pomyśleć, obejmują:
Przede wszystkim koszt kontroli dostępu do instancji może być bardzo wysoki. Zostało to omówione przez innych w tym wątku. Teoretycznie można to zrobić za pomocą tego sprawdzenia wskaźnika. Nie można tego jednak zrobić w czasie kompilacji i można to zrobić tylko w czasie wykonywania. Musisz więc zidentyfikować kontrolę dostępu każdego członka w czasie wykonywania, a kiedy zostanie naruszona, prawdopodobnie zostaną zgłoszone tylko wyjątki. Koszt jest wysoki.
Po drugie, kontrola dostępu dla klasy ma swój własny przypadek użycia, taki jak konstruktor kopiujący lub operator =. Trudno byłoby je wdrożyć, gdyby kontrola dostępu dotyczyła instancji.
Ponadto kontrola dostępu odbywa się głównie z perspektywy programowania / języka, w zakresie modularyzacji / kontroli dostępu do kodu / elementu członkowskiego, a nie danych.
źródło
To trochę arbitralna decyzja dotycząca projektu językowego. Na przykład w Rubim
private
naprawdę oznacza „prywatny”, ponieważ „tylko instancja ma dostęp do swoich prywatnych członków danych”. Jest to jednak nieco restrykcyjne.Jak wskazano w komentarzach, konstruktory kopiujące i operatory przypisania są typowymi miejscami, w których uzyskujesz bezpośredni dostęp do prywatnych danych członków innej instancji. Istnieją mniej oczywiste powody.
Rozważ następujący przypadek. Implementujesz listę połączoną OO. Lista połączona zawiera zagnieżdżoną klasę węzłów do zarządzania wskaźnikami. Możesz zaimplementować tę klasę węzła w taki sposób, że sama zarządza wskaźnikami (zamiast publicznych i zarządzanych przez listę wskaźników). W takim przypadku obiekty węzłów chciałyby zmodyfikować wskaźniki innych obiektów węzłów w innych miejscach niż typowy konstruktor kopiujący i operator przypisania.
źródło
Sztuką jest, aby pamiętać, że dane są
private
do klasy , a nie instancji klasy. Każda metoda w Twojej klasie może uzyskać dostęp do prywatnych danych dowolnej instancji tej klasy; nie ma sposobu, aby zachować prywatność danych wewnątrz instancji, chyba że zabronisz metod, które jawnie uzyskują dostęp do prywatnych danych członków innych instancji.źródło
Oprócz wszystkich powyższych odpowiedzi, rozważ niestandardowe konstruktory kopiowania, operatory przypisania i wszystkie inne funkcje, które napisałbyś dla klasy, które działają na innych instancjach . Potrzebujesz funkcji akcesorów dla wszystkich tych członków danych.
źródło
Dane prywatne pozostają prywatne, dopóki ktoś, kto ma do nich dostęp, nie ujawni ich innym.
Ta koncepcja dotyczy również innych sytuacji, takich jak:
Jak ktoś mógł wypłacić pieniądze? :)
źródło