Рассмотрим решение Мэтта Прайса .
- В C ++ «статический класс» не имеет значения. Ближайшим классом являются только статические методы и члены.
- Использование статических методов ограничит вас.
Вы хотите, выражаясь в семантике C ++, поместить свою функцию (для нее - это функция) в пространство имен.
Изменить 2011-11-11
В C ++ нет "статического класса". Ближайшим понятием будет класс с только статическими методами. Например:
// header
class MyClass
{
public :
static void myMethod() ;
} ;
// source
void MyClass::myMethod()
{
// etc.
}
Но вы должны помнить, что «статические классы» - это хаки в Java-подобных языках (например, C #), которые не могут иметь функции, не являющиеся членами, поэтому вместо этого им нужно перемещать их внутри классов как статические методы.
В C ++ вам действительно нужна функция, не являющаяся членом, которую вы объявляете в пространстве имен:
// header
namespace MyNamespace
{
void myMethod() ;
}
// source
namespace MyNamespace
{
void myMethod()
{
// etc.
}
}
Почему это?
В C ++ пространство имен более мощное, чем классы для шаблона «статический метод Java», потому что:
- статические методы имеют доступ к закрытым символам классов
- частные статические методы все еще видны (если они недоступны) всем, что несколько нарушает инкапсуляцию
- статические методы не могут быть объявлены заранее
- статические методы не могут быть перегружены пользователем класса без изменения заголовка библиотеки
- нет ничего, что может быть сделано статическим методом, который не может быть лучше, чем (возможно, друг) не-членская функция в том же пространстве имен
- Пространства имен имеют свою семантику (их можно объединять, они могут быть анонимными и т. Д.)
- и т.д.
Вывод: не копируйте / вставляйте этот шаблон Java / C # в C ++. В Java / C # шаблон является обязательным. Но в C ++ это плохой стиль.
Редактировать 2010-06-10
Был аргумент в пользу статического метода, потому что иногда нужно использовать статическую закрытую переменную-член.
Я немного не согласен, как показано ниже:
Решение "Static private member"
// HPP
class Foo
{
public :
void barA() ;
private :
void barB() ;
static std::string myGlobal ;
} ;
Во-первых, myGlobal называется myGlobal, потому что это все еще глобальная частная переменная. Взгляд на источник CPP прояснит, что:
// CPP
std::string Foo::myGlobal ; // You MUST declare it in a CPP
void Foo::barA()
{
// I can access Foo::myGlobal
}
void Foo::barB()
{
// I can access Foo::myGlobal, too
}
void barC()
{
// I CAN'T access Foo::myGlobal !!!
}
На первый взгляд, тот факт, что бесплатная функция barC не может получить доступ к Foo :: myGlobal, кажется хорошей вещью с точки зрения инкапсуляции ... Это круто, потому что кто-то, смотрящий на ГЭС, не сможет (если не прибегнет к саботажу) ) для доступа к Foo :: myGlobal.
Но если вы внимательно посмотрите на это, вы обнаружите, что это колоссальная ошибка: не только ваша частная переменная все равно должна быть объявлена в ГЭС (и, таким образом, видимой для всего мира, несмотря на то, что является частной), но Вы должны объявить в одной и той же HPP все (как во ВСЕХ) функции, которым будет разрешен доступ к нему !!!
Итак, использование личного статического члена - это все равно, что выходить на улицу в обнаженном виде со списком своих любовников, нанесенных татуировкой на вашей коже: никто не имеет права трогать, но каждый может посмотреть. И бонус: у каждого могут быть имена тех, кому разрешено играть с вашими друзьями.
private
действительно ...
: -D
Решение "Анонимные пространства имен"
Преимущество анонимных пространств имен в том, что они становятся частными.
Сначала заголовок ГЭС
// HPP
namespace Foo
{
void barA() ;
}
Просто чтобы быть уверенным, что вы заметили: нет ни бесполезного объявления ни barB, ни myGlobal. Это означает, что никто, читающий заголовок, не знает, что скрыто за barA.
Затем, CPP:
// CPP
namespace Foo
{
namespace
{
std::string myGlobal ;
void Foo::barB()
{
// I can access Foo::myGlobal
}
}
void barA()
{
// I can access myGlobal, too
}
}
void barC()
{
// I STILL CAN'T access myGlobal !!!
}
Как вы можете видеть, как и так называемое объявление "статического класса", fooA и fooB по-прежнему могут обращаться к myGlobal. Но никто не может. И никто за пределами этого CPP не знает fooB, и myGlobal даже существует!
В отличие от «статического класса», ходящего по обнаженной фигуре с ее адресной книгой, на которой нанесено татуирование, ее «анонимное» пространство имен полностью одето , которое выглядит довольно инкапсулированным AFAIK.
Это действительно имеет значение?
Если только пользователи вашего кода не являются диверсантами (в качестве упражнения я покажу вам, как можно получить доступ к закрытой части открытого класса, используя хак с грязным поведением, не определенным ...), что такое private
равно private
, даже если оно отображается в разделе private
класса, объявленного в заголовке.
Тем не менее, если вам нужно добавить еще одну "приватную функцию" с доступом к приватному члену, вы все равно должны объявить ее всему миру, изменив заголовок, что, на мой взгляд, парадокс: Если я изменю реализацию своего кода (часть CPP), то интерфейс (часть HPP) НЕ должен измениться. Цитата Леонидаса: " Это ENCAPSULATION! "
Редактировать 2014-09-20
Когда классы статические методы на самом деле лучше, чем пространства имен с функциями, не являющимися членами?
Когда вам нужно сгруппировать функции и передать эту группу в шаблон:
namespace alpha
{
void foo() ;
void bar() ;
}
struct Beta
{
static void foo() ;
static void bar() ;
};
template <typename T>
struct Gamma
{
void foobar()
{
T::foo() ;
T::bar() ;
}
};
Gamma<alpha> ga ; // compilation error
Gamma<Beta> gb ; // ok
gb.foobar() ; // ok !!!
Потому что, если класс может быть параметром шаблона, пространства имен не могут.