В чем разница между функциями member и nonnember в С++.
С++: Разница между функциями члена и нечлена
Ответ 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. - Делегирование методов, отличных от друзей, было подчеркнуто Саттер в Принципе интерфейсав котором он утверждает, что функции, которые доставляются с классом (в том же файле/в том же пространстве имен) и используют класс, являются логически частью интерфейса класса. Он повторяет в Исключительном С++.
Этот ответ становится довольно затяжным, но я подозреваю, что упустил из виду различия, которые другие могли бы найти критически... о хорошо.
Ответ 2
A (нестатическая) функция-член имеет неявный аргумент this
, член которого не является членом.
Синтаксически вы передаете этот неявный аргумент слева от оператора .
или ->
like.so()
или like->so()
вместо аргумента функции so( like )
.
Аналогично, при объявлении функции-члена вам нужно сделать это в классе, членом которого он является:
class Class {
public:
void a_public_member_function();
};
Функции, отличные от членов, объявляются вне любого класса (С++ вызывает это "в области пространства имен" ).
(Нестатические) функции-члены также могут быть виртуальными, но не-членные функции (и статические функции-члены) не могут.
Ответ 3
Функция-член не static
вызывается для объектов класса, к которому он принадлежит. Он неявно получает доступ к указателю this
, представляющему текущий объект. С помощью этого указателя он может легко получить доступ к другим членам и с полными правами доступа (т.е. Получить доступ к private
членам).
Функция нечлена не имеет неявного this
. В приведенном ниже примере bar
является функцией-членом, а freebar
- нет. Оба более или менее одинаковы, но обратите внимание, как bar
получает неявный указатель объекта через this
(также только bar
имеет привилегированный доступ к foo
членам, freebar
имеет доступ только к открытым членам).
class foo {
public:
void bar() {
this->x = 0; // equivalent to x = 0;
}
int x;
};
void freebar(foo* thefoo) {
thefoo->x = 1;
}
// ...
foo f;
f.bar();
// f.x is now 0
freebar(&f);
// f.x is now 1
Семантически функция-член больше, чем просто функция с неявным параметром. Он предназначен для определения поведения объекта (т.е. Объект автомобиля имеет drive()
, stop()
как функции-члены).
Обратите внимание, что существуют также функции-члены static
, которые имеют полные привилегии, но не получают неявный this
и не вызываются через экземпляр класса (а скорее через полное имя класса).
Ответ 4
В следующем коде f()
является функцией-членом класса Sample
, а g()
является нечленой функцией:
class Sample
{
void f();
};
void g();
Это очень просто. Поскольку f()
является членом класса Sample
, поэтому его называемая функция-член (класса Sample
). А так как g()
не является членом какого-либо класса, поэтому его называемая не-членная функция.
Ответ 5
Функция-член вызывается на объект и имеет доступ к полям класса.
Функции-члены могут быть полиморфными (с помощью ключевого слова virtual
), что необходимо для ООП.
Ответ 6
Функции-члены вызываются в экземплярах и имеют указатель this
; не-члены не делают.