Почему мы должны помещать частных членов в заголовки?

62

Закрытые переменные - это способ скрыть сложность и детали реализации для пользователя класса. Это довольно приятная особенность. Но я не понимаю, почему в C ++ нам нужно поместить их в заголовок класса. Я вижу два досадных недостатка в этом:

  • Загромождает заголовок от пользователя
  • Вызывает перекомпиляцию всех клиентских библиотек при изменении внутренних компонентов

Есть ли концептуальная причина этого требования? Это только для облегчения работы с компилятором?

Саймон Бергот
источник
вы можете объявить пустую структуру в заголовке, но тогда вы можете использовать указатели на такую ​​структуру только тогда, когда используете ее (и вы не можете выделить ее)
ratchet freak
3
@ratchetfreak: Нет, empty ( struct foo{};) не разрешен, но есть предварительные объявления ( struct foo;).
MSalters
@MSalters это то, что я имел в виду
трещотка урод
1
Позвольте мне добавить недостаток: * Написание заголовков частных функций в файле .h - огромная трата времени. (на мгновение забыв о занятиях с друзьями)
Джонни

Ответы:

68

Это происходит потому, что компилятор C ++ должен знать фактический размер класса, чтобы выделять нужный объем памяти при создании экземпляра. И размер включает в себя все члены, а также частные.

Один из способов избежать этого - использовать идиому Пимпл , объясненную Хербом Саттером в его «Гуру недели», серии № 24 и № 28 .

Обновить

Действительно, это (или, в более общем смысле, различие между заголовочным и исходным файлами и #includes) является основным препятствием в C ++, унаследованном от C. В те времена, когда создавался C ++ C, еще не было опыта крупномасштабной разработки программного обеспечения, где начинает вызывать реальные проблемы. Уроки, извлеченные с тех пор, были учтены разработчиками более новых языков, но C ++ связан с требованиями обратной совместимости, что делает действительно трудным решение такой фундаментальной проблемы в языке.

Петер Тёрёк
источник
Разве такого рода информация не содержится только в библиотеке классов? Используется ли для ссылки?
Саймон Бергот
@ Симон, что ты имеешь в виду под "библиотекой классов"?
Петер Тёрёк
Я имею в виду коллекцию объектных файлов, содержащую определение класса и методы
Саймон Бергот
7
Когда был создан C ++, AT & T / Bell Labs (в то время работодатель Stroustrups), безусловно, имели опыт крупномасштабной разработки на языке Си. Их программное обеспечение для телефонного коммутатора 5ESS в то время было, вероятно, самой крупной в мире одной программой на языке Си. Первые идеи об ОО уже видны в этой базе кода, и Cfront имитировал эти методы. Однако понятие privateболее современно.
MSalters
1
В C вы просто поместите распределитель в библиотечную функцию; клиент не сможет выделить такую ​​структуру вообще. Это немного увеличивает накладные расходы, но делает перенос кода между версиями тривиальным, так что это часто стоит. Тем не менее, это, как правило, приводит к стилю кода, который очень отличается от того, который видели в C ++.
Donal Fellows
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

Скорее всего, есть несколько причин. Хотя закрытые члены не могут быть доступны большинству других классов, они все же могут быть доступны для классов друзей. Так что, по крайней мере, в этом случае они могут понадобиться в заголовке, чтобы класс друга мог видеть, что они существуют.

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

Торстен Мюллер
источник