Perché gli oggetti della stessa classe hanno accesso ai dati privati ​​degli altri?


98

Perché gli oggetti della stessa classe hanno accesso ai dati privati ​​degli altri?

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;
}

Questo codice funziona. È perfettamente possibile per l'oggetto a accedere a dati privati ​​dall'oggetto be restituirli. Perché dovrebbe essere così? Penso che i dati privati ​​siano privati. (Ho iniziato cercando di capire i costruttori di copie nell'idioma pimpl, ma poi ho scoperto che non avevo nemmeno capito questa semplice situazione.)


18
Bene, come punto di partenza, non saresti in grado di implementare correttamente alcun costruttore di copia per nient'altro che le classi più semplici. Puoi pensare alle lezioni come al loro migliore amico :-)
Cameron

4
Pensa al privato dei loro clienti, ma tutti i dipendenti della classe hanno accesso
Martin Beckett

Grazie Cameron. Ha senso, ma allora perché questo accesso non è limitato solo ai costruttori di copia e agli operatori di assegnazione?
Keith

5
Oggetti dello stesso tipo spesso interagiscono molto. E nessuno ti obbliga a scrivere un metodo che distribuisca dati privati ​​di un'altra istanza. :)
UncleBens

4
Semplicemente perché, in fase di compilazione, il compilatore non ha modo di identificare lo stesso oggetto. L'applicazione di tale accesso richiederebbe il supporto in fase di esecuzione.
Chethan

Risposte:


80

Perché è così che funziona in C ++. In C ++ il controllo degli accessi funziona per classe , non per oggetto.

Il controllo dell'accesso in C ++ è implementato come funzionalità statica in fase di compilazione. Penso che sia piuttosto ovvio che non sia realmente possibile implementare alcun controllo di accesso significativo per oggetto in fase di compilazione. Solo il controllo per classe può essere implementato in questo modo.

Alcuni accenni al controllo per oggetto sono presenti nella specifica di accesso protetto , motivo per cui ha anche un proprio capitolo dedicato nello standard (11.5). Tuttavia, tutte le caratteristiche per oggetto descritte sono piuttosto rudimentali. Ancora una volta, il controllo degli accessi in C ++ è pensato per funzionare su base per classe.


9
+1. Il C ++ è grande per i meccanismi in fase di compilazione, non così grande per i meccanismi di esecuzione. Regola generale abbastanza buona.
Nemo

4
Il tuo "non è realmente possibile implementare alcun controllo di accesso significativo per oggetto in fase di compilazione". Perchè no? In void X::f(X&x), il compilatore è facilmente in grado di distinguere this->ae x.a. Non è (sempre) possibile che il compilatore lo sappia *thise in xrealtà sono lo stesso oggetto se x.f(x)viene invocato, ma potrei benissimo vedere un progettista di linguaggio trovare questo OK.
André Caron

@ AndréCaron Penso che questo sia in realtà un bollitore molto più grande di quanto tu lo faccia. Quando l'inlining non avviene, il compilatore dovrà sempre controllare se thise &xsono uguali. A peggiorare le cose questo in realtà finisce per essere un problema anche con X::f(Y& y), perché il nostro oggetto concreto potrebbe essere del tipo Zche eredita da entrambi Xe Y. Insomma, è un vero casino, non performante, difficile da far lavorare in modo sensato con MI.
Nir Friedman

@NirFriedman Penso che tu abbia frainteso il suggerimento. Durante la compilazione X::f(X& x), se ci sono accessi a x.a, non si compilerebbe. Nient'altro cambia, non è necessario inserire controlli, quindi le prestazioni dei programmi ancora validi non vengono influenzate. E non è suggerito come una modifica radicale al C ++ esistente, ma come qualcosa che i progettisti avrebbero potuto fare quando hanno introdotto privateoriginariamente.
Alexey Romanov

31

"Privato" non è realmente un meccanismo di controllo degli accessi nel senso di "Ho reso private le mie foto su Facebook in modo che tu non possa vederle".

In C ++, "private" dice semplicemente che queste sono parti di una classe che tu (il programmatore della classe) potresti cambiare nelle versioni future, ecc., E non vuoi che altri programmatori che usano la tua classe si affidino alla loro esistenza o funzionalità .

Se si desidera un vero controllo degli accessi, è necessario implementare tecniche di protezione dei dati autentiche.


13

Questa è una buona domanda e mi sono imbattuto in questa domanda di recente. Ho avuto alcune discussioni con i miei colleghi ed ecco il riassunto della nostra discussione: Questo è di progettazione. Ciò non significa che questo design sia totalmente ragionevole per tutti i casi, ma ci devono essere alcune considerazioni sul motivo per cui viene scelto il privato per classe. Le possibili ragioni a cui potremmo pensare includono:

Prima di tutto, il costo del controllo dell'accesso per istanza potrebbe essere molto alto. Questo è stato discusso da altri in questo thread. In teoria, questo può essere fatto tramite questo controllo del puntatore. Tuttavia, questa operazione non può essere eseguita in fase di compilazione e può essere eseguita solo in fase di esecuzione. Quindi devi identificare il controllo di accesso di ogni membro in fase di esecuzione, e quando viene violato probabilmente verranno sollevate solo eccezioni. Il costo è alto.

In secondo luogo, il controllo dell'accesso per classe ha il suo caso d'uso, come il costruttore di copie o l'operatore =. Sarebbe difficile implementarli se il controllo dell'accesso è per istanza.

Inoltre, il controllo dell'accesso è principalmente dal punto di vista della programmazione / linguaggio, per come modulare / controllare l'accesso al codice / membro, non ai dati.


12

È in qualche modo una decisione arbitraria di progettazione del linguaggio. In Ruby , ad esempio, privatesignifica veramente privato, come in "solo l'istanza può accedere ai propri membri di dati privati". Tuttavia, questo è un po 'restrittivo.

Come indicato nei commenti, i costruttori di copia e gli operatori di assegnazione sono luoghi comuni in cui si accede direttamente ai membri dei dati privati ​​di un'altra istanza. Ci sono ragioni meno ovvie per cui.

Considera il seguente caso. Stai implementando un elenco collegato OO. L'elenco collegato ha una classe di nodi nidificati per la gestione dei puntatori. È possibile implementare questa classe di nodi in modo tale che gestisca i puntatori da sé (invece di avere i puntatori pubblici e gestiti dalla lista). In tal caso, gli oggetti nodo vorranno modificare i puntatori di altri oggetti nodo in altri punti rispetto al tipico costruttore di copia e operatore di assegnazione.


4

Il trucco sta nel ricordare che i dati sono privateper la classe , non per l' istanza della classe. Qualsiasi metodo all'interno della tua classe può accedere ai dati privati ​​di qualsiasi istanza di quella classe; non c'è un modo per mantenere i dati privati ​​all'interno di un'istanza a meno che non si vietino metodi che accedono esplicitamente ai membri dei dati privati ​​di altre istanze.


1

Oltre a tutte le risposte precedenti, considera i costruttori di copia personalizzati, gli operatori di assegnazione e tutte le altre funzioni che scriveresti per una classe che opera su altre istanze . Avresti bisogno di funzioni di accesso per tutti quei membri di dati.


-8

I dati privati ​​rimangono privati ​​fino a quando qualcuno che vi ha accesso non li rivela ad altri.

Questo concetto si applica anche ad altre situazioni, come ad esempio:

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

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

private:
   int iTheSecretVault;
};

Come potrebbe qualcuno ritirare i soldi? :)


3
Questo esempio non implica che un'istanza di classe acceda ai membri dei dati privati ​​di un'altra istanza.
André Caron

@Andre, "Questo concetto si applica anche ad altre situazioni, come ..."
YeenFei

^ "altra situazione" è fuori tema per definizione, quindi il tuo esempio non ha rilevanza (e non sono sicuro che sarebbe informativo neanche da nessun'altra parte)
underscore_d

1
Questa spiegazione non è affatto corretta alla domanda.
Panda
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.