Чому об’єкти одного класу мають доступ до приватних даних один одного?


98

Чому об’єкти одного класу мають доступ до приватних даних один одного?

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

Цей код працює. Об'єкту a цілком можливо отримати доступ до приватних даних з об'єкта b та повернути його. Чому так має бути? Я думаю, що приватні дані є приватними. (Я почав, намагаючись зрозуміти конструктори копій у ідіомі pimpl, але потім я виявив, що навіть не розумію цієї простої ситуації.)


18
Ну, як вихідний пункт, ви не зможете належним чином реалізувати будь-які конструктори копій для нічого, крім найпростіших класів. Ви можете думати про заняття як про свого найкращого друга :-)
Камерон

4
Подумайте про приватних від своїх клієнтів, але всі працівники класу мають доступ
Мартін Бекетт

Дякую Камерон. Це має сенс, але чому тоді цей доступ не обмежується лише конструкторами копіювання та операторами призначення?
Кіт

5
Об'єкти одного типу часто взаємодіють багато. І ніхто не змушує вас написати метод, який передає приватні дані іншої інстанції. :)
UncleBens

4
Просто тому, що під час компіляції компілятор не може ідентифікувати свій той самий об'єкт. Для забезпечення такого доступу потрібна підтримка часу виконання.
Четман

Відповіді:


80

Тому що це працює в C ++. У C ++ контроль доступу працює на основі класу , а не на основі об'єкта.

Контроль доступу в C ++ реалізується як статична функція часу компіляції. Я думаю, що досить очевидно, що реально реалізувати будь-який змістовний контроль доступу до об'єктів під час компіляції. Таким чином можна реалізувати лише контроль за класом.

Деякі підказки управління об'єктом містяться в специфікаціях захищеного доступу , тому він навіть має власну спеціальну главу стандарту (11.5). Але все ж будь-які характеристики об'єкта, описані там, є досить рудиментарними. Знову ж таки, контроль доступу в C ++ повинен працювати на основі класу.


9
+1. C ++ є великим для механізмів компіляції, не таким великим для механізмів виконання. Досить гарне загальне правило.
Немо

4
Ваше "реально не реалізувати будь-який змістовний контроль доступу до об'єкта під час компіляції". Чому ні? У void X::f(X&x), компілятор легко здатний розрізнити this->aі x.a. Не завжди (завжди) можливо, компілятор це знає, *thisі xнасправді той самий об’єкт, якщо x.f(x)викликається, але я міг би дуже добре бачити, як мовний дизайнер вважає це нормальним.
Андре Карон

@ AndréCaron Я думаю, що це насправді набагато більший чайник з рибою, тоді ви це зробите. Коли вбудовування не відбувається компілятор завжди буде робити перевірку чи thisі &xте ж. Що ще гірше, це насправді навіть стає проблемою X::f(Y& y), тому що наш конкретний об'єкт може бути типу, Zякий успадковується від обох Xі Y. Коротше кажучи, це справжній безлад, а не виконавець, важко змусити розумно працювати з MI.
Нір Фрідман

@NirFriedman Я думаю, ви неправильно зрозуміли пропозицію. При компілюванні X::f(X& x), якщо є доступ до цього x.a, він не збирається. Нічого іншого не змінюється, не потрібно вставляти перевірки, тому на продуктивність ще дійсних програм це не впливає. І це не пропонується як суттєва зміна існуючого C ++, а як щось, що могли б зробити дизайнери при вступі privateоригіналу.
Олексій Романов

31

"Приватний" насправді не є механізмом контролю доступу в сенсі "я зробив свої фотографії у facebook приватними, тому ви їх не можете бачити".

У C ++ "приватний" просто говорить, що це частини класу, які ви (кодер класу) можете змінити у майбутніх версіях тощо. Ви не хочете, щоб інші кодери, що використовують ваш клас, покладалися на їх існування чи функціональність .

Якщо ви хочете справжнього контролю доступу, вам слід застосувати справжні методи захисту даних.


13

Це гарне запитання, і я нещодавно натрапив на це питання. У мене були деякі дискусії з колегами, і ось короткий підсумок нашої дискусії: Це за задумом. Це не означає, що ця конструкція цілком розумна для всіх випадків, але повинні бути певні міркування, чому для кожного класу вибирається приватне. Можливі причини, про які ми могли б подумати, включають:

Перш за все, вартість контролю доступу до примірника може бути дуже високою. Це обговорювали інші в цій темі. Теоретично це можна зробити за допомогою цієї перевірки вказівника. Однак це неможливо зробити під час компіляції, а це можна зробити лише під час виконання. Таким чином, ви повинні ідентифікувати контроль доступу кожного члена під час виконання, і коли він порушується, можливо, будуть висунуті лише винятки. Вартість висока.

По-друге, для контролю доступу в класі є власний випадок використання, наприклад конструктор копій або оператор =. Їх було б важко реалізувати, якщо контроль доступу є, наприклад,.

Крім того, контроль доступу в основному з точки зору програмування / мови, як модулювати / контролювати доступ до коду / члена, а не даних.


12

Це дещо довільне мовне рішення дизайну. В Рубі , наприклад, на privateсамому ділі означає приватна, як в «тільки , наприклад , може отримати доступ до його власним елементам даних». Однак це дещо обмежувально.

Як зазначено в коментарях, конструктори копій та оператори присвоєння є загальними місцями, де ви безпосередньо отримуєте доступ до приватних членів даних іншого примірника. Існують менш очевидні причини, чому.

Розглянемо наступний випадок. Ви реалізуєте пов'язаний список ОО. Список пов'язаних має вкладений клас вузлів для управління вказівниками. Ви можете реалізувати цей клас вузлів таким чином, що він керує самими вказівниками (а не мати покажчики загальнодоступними та керувати їх списком). У такому випадку у вас будуть об'єкти вузлів, які хочуть змінити покажчики інших об'єктів вузла в інших місцях, що є типовим конструктором копіювання та оператором призначення.


4

Хитрість полягає в тому, щоб пам'ятати про те , що дані privateв класі , а НЕ примірника класу. Будь-який метод у вашому класі може отримати доступ до приватних даних будь-якого екземпляра цього класу; не існує способу збереження приватних даних у межах екземпляра, якщо ви не забороняєте методи, які явно отримують доступ до приватних даних членів інших інстанцій.


1

На додаток до всіх відповідей вище, розгляньте власні конструктори копій, оператори присвоєння та всі інші функції, які ви б написали для класу, який працює в інших екземплярах . Вам потрібні функції аксесуарів для всіх цих членів даних.


-8

Приватні дані залишаються приватними, поки хтось, хто має доступ до них, не відкриє їх іншим.

Ця концепція застосовується і до інших ситуацій, таких як:

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

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

private:
   int iTheSecretVault;
};

Як хто-небудь міг зняти гроші? :)


3
Цей приклад не передбачає, що один екземпляр класу має доступ до приватних членів даних іншого примірника.
Андре Карон

@Andre, "Ця концепція стосується і інших ситуацій, таких як ..."
YeenFei

^ "інша ситуація" є поза темою за визначенням, тому ваш приклад не має жодної актуальності (і я не впевнений, що це було б інформативно і деінде)
underscore_d

1
Це зовсім не правильне пояснення питання.
Панда
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.