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