приватная статическая функция-член или свободная функция в анонимном пространстве имен? - PullRequest
32 голосов
/ 06 июля 2011

Я недавно сделал стилистическое изменение и хотел посмотреть, как к этому относятся другие программисты на С ++ и есть ли у него недостатки.

По сути, когда мне нужна была служебная функция, которая не требует доступа к данному члену класса, я обычно делал что-то вроде этого:

file.h

class A {
public:
    // public interface
private:
    static int some_function(int);
};

file.cpp

int A::some_function(int) {
    // ...
}

Но в последнее время я предпочел сделать что-то более похожее на это:

file.cpp

namespace {
    int some_function(int) {

    }
}
// the rest of file.cpp

Вот мой мыслительный процесс:

  • это на один файл меньше правки
  • просто указав функцию в заголовочном файле, вы можете подсказать детали реализации которые не нуждаются в разоблачении (даже если они не доступны публично).
  • если необходимо изменить прототип функции, необходимо перекомпилировать только один файл.

Последний самый убедительный для меня. Итак, мой вопрос: Есть ли минусы в этом?

Они функционально эквивалентны для большинства целей, о которых я могу думать. Мне кажется, что функция private static почти всегда может быть преобразована в свободную функцию в анонимном namespace.

EDIT : Одна вещь, которая приходит на ум, заключается в том, что функция private static будет иметь доступ к private членам, если ей будет дан указатель на объект для работы, но если это так, почему не сделать его не static членом?

Что вы, ребята, думаете?

Ответы [ 7 ]

22 голосов
/ 06 июля 2011

Если функция используется только в одном исходном файле, имеет смысл определить ее там. Если никто не использует его, он не принадлежит заголовку.

Как вы говорите, это уменьшает зависимости и потенциально может сохранить некоторые перекомпиляции.

7 голосов
/ 06 июля 2011

Я начал делать это несколько лет назад и никогда не находил никаких реальных отступлений. Все, что объект использует, но само по себе не изменяет состояние объекта и не нуждается в использовании где-либо еще, я хотел бы поместить в анонимное пространство имен в файле реализации.

5 голосов
/ 06 июля 2011

Лично единственные статические функции, которые я использую, - это заводские функции, например:

class Angle {
public:
    static Angle FromDegree (float v);
    static Angle FromRadians (float v);

    ...
private:
    Angle (float degree);
};

Все, что не требует частного доступа, становится бесплатной функцией.Все, что не является частью общедоступного интерфейса, по возможности не размещается в публичном месте (в соответствии с вашим новым подходом).

Статья Скотта Мейера "Как функции, не являющиеся членами, улучшают инкапсуляцию" *Примерно 1007 * описывает тот же подход:

Минимальность и инкапсуляция

В Effective C ++ я высказался за полные и минимальные интерфейсы классов.Такие интерфейсы позволяют клиентам классов делать все, что они могут разумно делать, но классы содержат не больше функций-членов, чем это абсолютно необходимо.Я написал, что добавление функций сверх минимума, необходимого для того, чтобы клиенты могли выполнять свою работу, снижает понятность и удобство сопровождения класса, а также увеличивает время компиляции для клиентов.Джек Ривз писал, что добавление функций-членов сверх тех, которые действительно необходимы, нарушает принцип открытого / закрытого доступа, приводит к появлению интерфейсов толстых классов и в конечном итоге приводит к программному гниению.Это достаточное количество аргументов для минимизации числа функций-членов в классе, но теперь у нас есть дополнительная причина: отказ сделать это уменьшает инкапсуляцию класса.

Конечно, минимальный интерфейс класса не обязательнолучший интерфейс.В Effective C ++ я заметил, что добавление функций сверх тех, которые действительно необходимы, может быть оправданным, если оно значительно повышает производительность класса, облегчает использование класса или предотвращает возможные ошибки клиента.Основываясь на своей работе с различными струноподобными классами, Джек Ривз заметил, что некоторые функции просто «не чувствуют» себя правильно, когда становятся не-членами, даже если они могут быть не-друзьями-не-членами.«Лучший» интерфейс для класса может быть найден только путем уравновешивания многих конкурирующих задач, из которых степень инкапсуляции всего одна.

Тем не менее, урок этой статьи должен быть понятен.Несмотря на общепринятое мнение, использование функций, не являющихся членами, не являющимися членами, улучшает инкапсуляцию класса, а предпочтение таким функциям по сравнению с функциями-членами облегчает проектирование и разработку классов с полными и минимальными интерфейсами (или близкими к минимальным).Аргументы о естественности результирующего синтаксиса вызова, как правило, необоснованны, и принятие пристрастия к функциям, не являющимся членами, не являющимися членами, приводит к стратегиям упаковки для интерфейса класса, которые минимизируют зависимости компиляции клиента, в то же время максимизируя число удобных для них функций.

Пришло время отказаться от традиционных, но неточных представлений о том, что значит быть объектно-ориентированным.Вы настоящий сторонник инкапсуляции?Если да, то я знаю, что вы будете воспринимать функции, не являющиеся друзьями, не являющимися членами, с тем рвением, которого они заслуживают.

5 голосов
/ 06 июля 2011

Я не вижу никаких минусов в использовании анонимного пространства имен.Если вы можете кодировать функцию с пользой, не имея доступа к членам класса, то вам следует это сделать, потому что она отделяет ее от самого класса (например, как стандартные алгоритмы работают на парах итераторов).

4 голосов
/ 06 июля 2011

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

Статические константные переменные могут документировать ограничения и ожиданиякоторые полезны для клиентского кода, поэтому они идут в заголовке.

Статическим функциям может понадобиться доступ к закрытым элементам данных, поэтому они идут в заголовке , если им нужно .

0 голосов
/ 21 декабря 2017

Если вы используете единую сборку (т. Е. # Включая все файлы .cpp проекта в один модуль компиляции для ускорения времени компиляции), вы рискуете столкнуть имена с другими функциями в анонимных пространствах имен.

Это единственный недостаток, который я нашел.

0 голосов
/ 06 июля 2011

Вся причина статической функции в отличие от глобальной функции заключается в том, что она обращается к закрытым членам класса.Если это не так, используйте бесплатную функцию.Этот анализ не является полным ответом, пока у нас не будет всех 3 альтернативных способов сделать это:

свободная функция:

void f() { /* cannot access private members of any class */ }

статическая функция:

class A {
public:
   static void g() { /* can access private members of class A */ }
};

функции друга:

    class A {
    public:
       friend void h();
    };
    class B {
    public:
       friend void h();
   };
   void h() { /* can access private members of both class A and class B */ }

Реальная проблема с тем, как c ++ делает это, заключается в том, что вызов функции выглядит иначе:

int main() {
   f();
   A::g();
   h();
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...