Подтвердить что ты не робот

С++: Разница между функциями члена и нечлена

В чем разница между функциями member и nonnember в С++.

4b9b3361

Ответ 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; не-члены не делают.