Существует несколько различий между функцией-членом (которую я сейчас назову метод ) и свободной функцией (которую я сейчас назову функция ).
Во-первых, давайте просто заявим, что они не , поэтому отличаются. Объектный код, как правило, может быть скомпилирован до C (или ассемблера), которые являются процедурными языками без понятия методов. Тогда и методы, и функции называются как подпрограммы.
Теперь, когда это не так, давайте посмотрим на различия. Их можно разделить на две категории: концептуальные и синтаксические.
синтаксически
Синтаксис является очевидной частью любого языка, поэтому его легче всего убрать.
Первое замечание: в C ++ есть два различных вида методов (и ряд других языков): static
и обычные методы.
Оба вида методов имеют полный доступ к внутренним объектам класса (protected
и private
разделам), а также (конечно) к доступу к интерфейсу класса public
.
static
методы эквивалентны friend
функциям (за исключением некоторых различий в области видимости).
В обычном методе специальное ключевое слово (this
в C ++) позволяет получить доступ к текущему объекту, для которого был вызван метод (с помощью операторов .
, ->
, .*
или ->*
).
Обычный метод может быть квалифицирован const
и / или volatile
, что позволяет (соответственно) const
и / или volatile
квалифицированным объектам. Например, метод не const
не может быть вызван для объекта const
. Это можно рассматривать как квалификацию this
в методе, то есть void Foo::bar() const
имеет this
типа Foo const*
.
Обычный метод может быть помечен как virtual
. Виртуальность обеспечивает полиморфизм во время выполнения путем включения переопределения. Я не буду подробно останавливаться на этом механизме, давайте просто заметим, что функции не могут быть виртуальными.
Часто игнорируемым моментом является то, что методы (как static
, так и обычные) находятся в пределах класса. Это важно для поиска имени (других методов или атрибутов / переменных), поскольку это означает, что элементы класса имеют приоритет во время поиска от метода к элементам, объявленным вне класса.
Поскольку квалификация с использованием this->
перед атрибутом или методами не является обязательной, это удобно в обычных методах, хотя может привести к незначительным ошибкам. В статических методах он избегает определения по имени класса статических атрибутов и методов, к которым нужно обращаться.
Теперь, когда основные синтаксические различия установлены, давайте проверим концептуальные различия.
Концептуально
ООП обычно сводит воедино состояние и поведение (этого состояния). Это делается путем создания классов, которые группируют атрибуты (состояние) и поведение (методы) и (в теории), утверждая, что только методы могут воздействовать на состояние. Поэтому в ООП методы отвечают за реализацию поведения класса.
Методы участвуют в инкапсуляции состояния (освобождая клиентов от деталей реализации) и сохраняя инварианты класса (утверждения о состоянии класса, которые сохраняются от его рождения до его смерти, что бы вы ни делали с ним).
C ++
В C ++, как мы видели ранее, это делается с помощью различных уровней доступа (public
, protected
и private
) и предоставления доступа к уровням, отличным от public
, к ограниченной части код. Обычно атрибуты будут частными и, следовательно, доступны только для методов класса (и, возможно, некоторым друзьям, для синтаксических изысков).
Примечание: я призываю вас не использовать атрибуты protected
, сложно отследить их модификации, и поскольку набор производных классов не ограничен ... их реализация не может быть легко изменена впоследствии.
Однако следует помнить, что C ++ не поощряет вздутие интерфейса множеством методов.
Проблема в том, что, поскольку методы отвечают за поддержание инвариантов, чем их больше, тем больше распространяется ответственность, что затрудняет поиск ошибок и обеспечение их корректности.Кроме того, поскольку методы зависят от внутренних компонентов класса, это делает изменение более дорогостоящим.
Вместо этого в C ++ обычно рекомендуется писать минимальный набор методов и делегировать оставшуюся часть поведения не-* 1090.* функции (при условии, что это не слишком увеличивает стоимость).
- См. взгляд Саттера на
std::string
в Монолит Unstrung . - Саттер подчеркнул, что делегирование методов, не являющихся друзьями, в его Принципе интерфейса , в котором он утверждает, что функции, которые поставляются с классом (в том же файле / в том же пространстве имен) и используют класс, являются логически частьюинтерфейс класса.Он повторяет в «Исключительном C ++».
Этот ответ становится довольно многословным, но я подозреваю, что я упустил из виду различия, которые другие сочли бы критическими ... о, хорошо.