Ответ на вопрос о том, почему мы помещаем закрытые переменные-члены в заголовки C ++, состоит в том, что размер класса должен быть известен в точках, где экземпляры объявлены, чтобы компилятор мог генерировать код, который соответствующим образом перемещается по стеку.
Почему мы должны помещать частных членов в заголовки?
Но есть ли причина объявлять частные функции в определении класса?
Альтернативой может быть, по сути, идиома прыщей, но без лишней косвенности.
Эта языковая особенность больше, чем историческая ошибка?
Если вы разрешаете добавлять методы в класс вне его определения, они могут быть добавлены кем угодно , в любом файле.
Это сразу же предоставит всем клиентским кодам простой доступ к закрытым и защищенным элементам данных.
После того, как вы закончили определение класса, нет никакого способа пометить некоторые файлы как специально благословленные автором, чтобы расширить его - есть только плоские единицы перевода. Таким образом, единственный разумный способ сообщить компилятору, что определенный набор методов является официальным или благословенным автором класса, - это объявить их внутри класса.
Обратите внимание, что у нас есть прямой доступ к памяти в C ++, что означает, что обычно просто создать теневой тип с тем же макетом памяти, что и у вашего класса, добавить мои собственные методы (или просто сделать все данные общедоступными), и
reinterpret_cast
. Или я могу найти код вашей частной функции или разобрать его. Или ищите адрес функции в таблице символов и вызывайте или напрямую.Эти спецификаторы доступа не пытаются предотвратить эти атаки, потому что это невозможно. Они только указывают, как должен использоваться класс.
источник
Принятый ответ объясняет это для виртуальных частных функций, но он отвечает только на один конкретный аспект вопроса, который значительно более ограничен, чем то, что задавал ОП. Итак, нам нужно перефразировать: почему мы должны объявлять не виртуальные частные функции в заголовках?
Другой ответ вызывает тот факт, что классы должны быть объявлены в одном блоке - после чего они запечатаны и не могут быть добавлены. Это то, что вы будете делать, опуская объявление частного метода в заголовке, а затем пытаясь определить его в другом месте. Хороший вопрос. Почему некоторые пользователи этого класса должны иметь возможность расширять его так, чтобы другие пользователи не могли наблюдать? Частные методы являются его частью и не исключаются из этого. Но затем вы спрашиваете, почему они включены, и это кажется немного тавтологическим. Почему классные пользователи должны знать о них? Если бы они не были видны, пользователи не могли бы добавить ни одного, и эй Presto.
Итак, я хотел бы дать ответ, который вместо того, чтобы просто включать частные методы по умолчанию, дает определенные моменты в пользу того, чтобы они были видны пользователям. Механистическая причина для не-виртуальных частных функций, требующих публичного объявления, дана в GotW # 100 Херба Саттера об идиоме Pimpl в качестве части ее обоснования. Я не буду рассказывать о Пимпле здесь, так как уверен, что мы все знаем об этом. Но вот соответствующий бит:
Саттер, конечно, является чрезвычайно надежным источником в качестве члена Комитета, поэтому он знает «обдуманное дизайнерское решение», когда видит его. И идея требовать публичного объявления частных методов как способа избежать измененной семантики или случайно нарушенной доступности позже, вероятно, является наиболее убедительным обоснованием. К счастью, все это казалось довольно бессмысленным до сих пор!
источник
Есть две причины для этого.
Во-первых, следует понимать, что спецификатор доступа предназначен для компилятора и не имеет отношения во время выполнения. Доступ к закрытому члену вне области видимости - ошибка компиляции .
сжатость
Рассмотрим функцию, которая короткая, одна или две строки. Он существует для того, чтобы уменьшить репликацию кода в другом месте, что также имеет преимущество в том, что он может изменять то, как алгоритм или что-то еще работает в одном месте вместо многих (например, изменение алгоритма сортировки).
Вы бы предпочли иметь быструю одну или две строки в заголовке, или там есть прототип функции плюс где-нибудь реализация? Его легче найти в заголовке, а для коротких функций гораздо сложнее иметь отдельную реализацию.
Есть еще одно важное преимущество:
Встроенные функции
Закрытая функция может быть встроенной, и это обязательно требует, чтобы она была в заголовке. Учти это:
Закрытая функция может быть встроена вместе с публичной функцией. Это делается на усмотрение компилятора, так как
inline
ключевое слово технически является предложением , а не требованием.источник
inline
, поэтому нет смысла использовать ключевое слово там..cpp
файле функцию , не являющуюся членом, которая указывается функциями-членами, которые определены вне определения класса, но такая функция не будет закрытой.Еще одна причина иметь закрытые методы в заголовочном файле: Есть случаи, когда открытый встроенный метод не намного больше, чем вызов одного или нескольких закрытых методов. Наличие в заголовке приватных методов означает, что вызов общедоступного метода может быть полностью встроен в реальный код приватных методов, и встраивание не прекращается при вызове приватного метода. Даже из другой единицы компиляции (и публичные методы обычно вызываются из разных единиц компиляции).
Конечно, есть и причина, по которой компилятор не может обнаружить проблемы с разрешением перегрузки, если он не знает все методы, включая частные.
источник
Это позволяет этим функциям получать доступ к закрытым членам. В противном случае вам все
friend
равно понадобится их в шапке.Если какая-либо функция может получить доступ к закрытым членам класса, тогда private будет бесполезен.
источник