Чому нам потрібно ставити приватних членів у заголовки?


62

Приватні змінні - це спосіб приховати деталі складності та реалізації для користувача класу. Це досить приємна особливість. Але я не розумію, чому в c ++ нам потрібно помістити їх у заголовок класу. Я бачу два прикрих недоліки цього:

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

Чи існує концептуальна причина цієї вимоги? Це лише полегшити роботу компілятора?


ви можете оголосити порожню структуру в заголовку, але тоді ви можете використовувати вказівники на таку структуру лише тоді, коли ви її використовуєте (а ви не можете виділити її)
ratchet freak

3
@ratchetfreak: Ні, порожній ( struct foo{};) не дозволений, але попередні декларації ( struct foo;) є.
MSalters

@MSalters ось що я мав на увазі
храповий

1
Дозвольте додати і зворотний бік: * Запис приватних заголовків функцій у файл .h - це велика витрата часу. (забувши на хвилину заняття з друзями)
Jonny

Відповіді:


68

Це тому, що компілятор C ++ повинен знати фактичний розмір класу, щоб виділити потрібний об'єм пам'яті при створенні інстанцій. І розмір включає всіх членів, також приватних.

Одним із способів уникнути цього є використання ідіоми Pimpl , поясненої Герб Саттер у своїх серіях «Гуру тижня» №24 та №28 .

Оновлення

Дійсно, це (або загалом, розрізнення заголовка / вихідного файлу #include) є головною перешкодою в C ++, успадкованому від C. Ще за часів створення C ++ C, ще не було досвіду розробки масштабного програмного забезпечення, де це починає викликати реальні проблеми. Дизайнери новіших мов прислухалися до уроків, які отримали з тих пір, але C ++ пов'язаний з вимогами про відсталу сумісність, що робить цю проблему справді важкою мовою.


Чи не є така інформація лише в бібліотеці класів? Чи використовується для зв’язування?
Саймон Берго

@Simon, що ти розумієш під "бібліотекою класів"?
Péter Török

Я маю на увазі колекцію об'єктних файлів, що містять визначення класу та методи
Саймон Берго

7
Коли було створено C ++, AT&T / Bell Labs (роботодавець Stroustrups на той час), безумовно, мав досвід великомасштабної розробки C. Їх програмне забезпечення для телефонних комутаторів 5ESS на той момент було, мабуть, найбільшою єдиною програмою C у світі. Ранні ідеї про ОО вже видно в цій кодовій базі, і Cfront наслідував ці методи. Однак поняття privateє більш сучасним.
MSalters

1
У C ви просто помістите розподільник у функцію бібліотеки; клієнт взагалі не міг би виділити таку структуру. Це трохи збільшує накладні витрати, але робить міграцію коду між версіями тривіальною, тому часто варто. Однак це, як правило, призводить до стилю коду, який дуже відрізняється від стилю C ++.
Стипендіати Доналу

15

Визначення класу повинно бути достатнім для компілятора, щоб створити однаковий макет у пам'яті, де б ви не використовували об'єкт класу. Наприклад, подано щось на зразок:

class X { 
    int a;
public:
    int b;
};

Зазвичай компілятор матиме aзміщення 0 та bзміщення 4. Якщо компілятор бачив це як раз:

class X { 
public:
    int b;
};

Було б "подумано", що bмає бути зі зміщенням 0, а не зсувом 4. Коли код, використовуючи таке визначення, призначене b, код, що використовує перше визначення, побачить aотримати змінені, і навпаки.

Звичайний спосіб мінімізувати ефекти внесення змін до приватних частин класу зазвичай називають ідіомою pimpl (про яку я впевнений, що Google може дати велику кількість інформації).


1
Я прошу про проектне рішення. Звичайно, вам потрібно буде десь поставити декларацію приватного члена, щоб мова могла працювати. Але чому він повинен бути в заголовку, а не в більш приватному місці?
Саймон Берго

7
@Simon: Заголовок - це все, що компілятор бачить, щоб сказати, як виглядає клас / структура. Були обговорені питання про те, щоб додати щось подібне до модулів до C ++, що приховало б подібні дані трохи більше, але до цих пір воно не було затверджено (хоча воно також не було повністю відмінено).
Джеррі Труну

3
І все-таки тривіальним правилом було б виділяти такі ".cpp-визначені" приватні члени останніми. Це означає, що компенсації публічних та "нормальних" приватних членів не залежатимуть від них. Істинною причиною IMO є те, що ви не можете успадкувати такий клас, оскільки похідна частина повинна наслідувати навіть тих приватних членів.
MSalters

3

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

Перекомпіляція залежних файлів може залежати від вашої структури include. Включення .h-файлів у .cpp-файл замість іншого заголовка може у деяких випадках запобігати довгим ланцюгам перекомпіляцій.

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