Пространство имен + функции против статических методов в классе - PullRequest
257 голосов
/ 16 сентября 2009

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

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

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

Ответы [ 7 ]

224 голосов
/ 16 сентября 2009

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

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

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

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

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

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

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

Расширение I

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

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

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

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

Расширение II

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

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

Расширение 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

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

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

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

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

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

Заключение

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

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

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

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

52 голосов
/ 16 сентября 2009

Есть много людей, которые не согласны со мной, но вот как я это вижу:

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

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

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

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

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

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


В ответ на комментарии: да, статические методы и статические данные имеют тенденцию к чрезмерному использованию. Вот почему я предложил только два связанных сценария, где я думаю, что они могут быть полезны. В конкретном примере 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;

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

12 голосов
/ 16 сентября 2009

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

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

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

3 голосов
/ 16 сентября 2009

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

0 голосов
/ 16 апреля 2015

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

0 голосов
/ 13 ноября 2011

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

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