Рассмотрим решение Мэтта Прайса .
- В 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.
Но если вы внимательно посмотрите на это, то обнаружите, что это колоссальная ошибка: не только ваша частная переменная все равно должна быть объявлена в ГЭС (и, таким образом, видимой для всего мира, несмотря на то, что является частной), но вы должны объявить в той же ГЭС все (как во ВСЕХ) функции, которым будет разрешен доступ к ней !!!
Таким образом, использование закрытого статического члена - это все равно, что выходить на улицу в обнаженном виде со списком своих любовников, нанесенных татуировкой на вашей коже: никто не имеет права прикасаться, но каждый может посмотреть. И бонус: у каждого могут быть имена тех, кому разрешено играть с вашими друзьями.
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) НЕ должен изменяться. Цитируя Леонидаса: « Это ЗАДЕРЖКА! »
Изменить 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 !!!
Потому что, если класс может быть параметром шаблона, пространства имен не могут.