Пространство имен + функции против статических методов в классе

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

  • Запишите эти функции и поместите их в мое пространство имен MyMath и обратитесь к ним через MyMath::XYZ()
  • Создайте класс с именем MyMath и сделайте эти методы статичными и обратитесь к аналогичному MyMath::XYZ()

Почему я должен выбирать один из них в качестве средства для организации моего программного обеспечения?

Ответ 1

По умолчанию используйте функции с именами.

Классы должны создавать объекты, а не заменять пространства имен.

В объектно-ориентированном коде

Скотт Мейерс написал целый предмет для своей эффективной книги на С++ по этой теме: "Предпочитайте функции, не являющиеся членами-членами, для функций-членов". Я нашел онлайн-ссылку на этот принцип в статье из Herb Sutter: http://www.gotw.ca/gotw/084.htm

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

Функции с именами, если только объявленный "друг" не имеет доступа к внутренним классам класса, тогда как статические методы имеют.

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

Расширение I

Добавление кода в интерфейс класса.

В С# вы можете добавлять методы в класс, даже если у вас нет доступа к нему. Но в С++ это невозможно.

Но, все еще на С++, вы все равно можете добавить функцию с именами, даже в класс, который кто-то написал для вас.

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

Расширение II

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

Для пространств имен функции из одного и того же пространства имен могут быть объявлены в нескольких заголовках (наиболее подходящим примером является почти стандартная функция swap).

Расширение III

Основная прохлада пространства имен заключается в том, что в некотором коде вы можете не упоминать об этом, если используете ключевое слово "using":

#include <string>
#include <vector>

// Etc.
{
   using namespace std ;
   // Now, everything from std is accessible without qualification
   string s ; // Ok
   vector v ; // Ok
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

И вы можете даже ограничить "загрязнение" одним классом:

#include <string>
#include <vector>

{
   using std::string ;
   string s ; // Ok
   vector v ; // COMPILATION ERROR
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

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

И это невозможно сделать со статическими методами в классах.

Итак, пространства имен С++ имеют свою собственную семантику.

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

Например, если у вас есть пространство имен A с функцией AAA, пространство имен B с функцией BBB, вы можете объявить пространство имен C и привести AAA и BBB в это пространство имен с использованием ключевого слова.

Заключение

Пространства имен относятся к пространствам имен. Классы предназначены для классов.

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

Не используйте классы, если вам нужны пространства имен.

И в вашем случае вам нужны пространства имен.

Ответ 2

Есть много людей, которые не согласились бы со мной, но я так понимаю:

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

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

Например, в вашем случае спросите себя: "Что такое MyMath?" Если MyMath не определяет тип объекта, я бы сказал: не делайте его классом.

Но, как я уже сказал, я знаю, что есть много людей, которые (даже яростно) не согласятся со мной на этом (в частности, разработчики Java и С#).

Ответ 3

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

В противном случае используйте функции с именами.


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

template<typename T, int decimalPlaces>
class MyMath
{
   // routines operate on datatype T, preserving at least decimalPlaces precision
};

// math routines for manufacturing calculations
typedef MyMath<double, 4> CAMMath;
// math routines for on-screen displays
typedef MyMath<float, 2> PreviewMath;

Если вам это не нужно, тогда обязательно используйте пространство имен.

Ответ 4

Вы должны использовать пространство имен, поскольку пространство имен имеет много преимуществ перед классом:

  • Вам не нужно определять все в одном заголовке
  • Вам не нужно раскрывать всю свою реализацию в заголовке
  • Вы не можете using член класса; вы можете using член пространства имен
  • Вы не можете using class, хотя using namespace не всегда так хороша.
  • Использование класса подразумевает, что есть какой-то объект, который будет создан, когда действительно нет

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

Ответ 5

Я бы предпочел пространства имен, таким образом, вы можете иметь личные данные в анонимном пространстве имен в файле реализации (поэтому он не должен отображаться в заголовке вообще, а не в членах private). Другим преимуществом является то, что при использовании using вашего пространства имен клиенты методов могут отказаться от указания MyMath::

Ответ 6

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

Ответ 7

Еще одна причина использования класса - опция для использования спецификаторов доступа. Затем вы можете разбить свой публичный статический метод на более мелкие частные методы. Открытый метод может вызывать несколько частных методов.