c ++: разница между функциями-членами и не-членами - PullRequest
31 голосов
/ 07 мая 2011

В чем разница между функциями-членами и не-числами в c ++.

Ответы [ 6 ]

25 голосов
/ 07 мая 2011

Существует несколько различий между функцией-членом (которую я сейчас назову метод ) и свободной функцией (которую я сейчас назову функция ).

Во-первых, давайте просто заявим, что они не , поэтому отличаются. Объектный код, как правило, может быть скомпилирован до 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 ++».

Этот ответ становится довольно многословным, но я подозреваю, что я упустил из виду различия, которые другие сочли бы критическими ... о, хорошо.

17 голосов
/ 07 мая 2011

A (нестатический) функция-член имеет неявный аргумент this, не являющийся членом - нет.

Синтаксически, вы передаете этот неявный аргумент слева отоператор . или -> like.so() или like->so() вместо аргумента функции so( like ).

Аналогично, при объявлении функции-члена это необходимо сделать в классекоторый является членом:

class Class {
public:
    void a_public_member_function();
};

Функции, не являющиеся членами, вместо этого объявляются вне какого-либо класса (C ++ называет это «в области пространства имен»).

(Нестатические) функции-члены могуттакже может быть virtual , но функции, не являющиеся членами (и статические функции-члены), не могут.

9 голосов
/ 07 мая 2011

Не- 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, и при этом они не вызываются через экземпляр класса (а скорее через полное имя класса).

6 голосов
/ 07 мая 2011

В следующем коде f() является функцией-членом класса Sample, а g() является функцией, не являющейся членом:

class Sample
{
  void f();
};

void g();

Это очень просто.Поскольку f() является членом класса Sample, то и называется его функцией-членом (класса Sample).А поскольку g() не является членом какого-либо класса, его называют функцией, не являющейся членом.

3 голосов
/ 07 мая 2011

Функция-член вызывается для объекта и имеет доступ к полям класса.

Функции-члены могут быть полиморфными (через ключевое слово virtual), что важно для ООП.

1 голос
/ 07 мая 2011

Функции-члены вызываются на экземплярах и имеют доступный указатель this; не являющиеся членами не.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...