Когда использовать ключевое слово «статический» в классе C++?
-
03-07-2019 - |
Вопрос
Код
static void MyClass::ThreadEntryStatic()
{
//...
}
void MyClass::Begin()
{
CreateThread(..,ThreadEntryStatic,..);
}
В каком случае нам следует использовать статику в классе?
Решение
Есть три места, где можно использовать ключевое слово static.Один из них находится в объявлении структуры/класса, когда этот контекст означает, что метод является методом класса, а не методом экземпляра.Это означает, что этот метод вызывается напрямую, и вам не нужен экземпляр.Из этого статического метода вы не можете получить доступ к переменным экземпляра.
В MyClass.h
struct MyClass
{
static void ThreadEntryStatic();
void Begin();
};
В MyClass.cpp
void MyClass::ThreadEntryStatic()
{
}
void MyClass::Begin()
{
CreateThread(.., MyClass::ThreadEntryStatic, ...);
}
Второй случай, когда используется ключевое слово static, находится в области файла, где вы не хотите, чтобы видимость объявленной переменной была видимой за пределами файла.Для этого вы также можете использовать анонимное пространство имен.
Третий случай, когда ключевое слово static используется в области действия метода, и значение сохраняется между выполнениями функции (и инициализируется присвоением в первый раз).
Другие советы
Если вы используете статические методы в нескольких потоках, вам нужно уделять очень пристальное внимание синхронизации вашего кода.По моему мнению, при многопоточном программировании я стараюсь использовать отдельный экземпляр моего объекта или рабочего элемента для каждого потока и вообще избегаю статических или общих данных любого типа.Конечно, это не всегда возможно, поэтому многопоточность остается одной из самых сложных областей программирования.
В качестве конкретного примера,
class Test{
static void foo();
};
static void Test::foo(){
// code here
}
не будет компилироваться, вы не сможете объявить функцию с ключевым словом static вне объявления класса.Вам просто нужно удалить ключевое слово static при реализации функции.
class Test{
static void foo();
};
void Test::foo(){
// code here
}
Несколько человек затронули эту тему, но static
используется для внутренней связи, не следует использовать, вместо этого следует использовать анонимное пространство имен:
namespace
{
void myInternallyLinkedFunction()
{
// do something
}
int myInternallyLinkedInteger;
class myInternallyLinkedClass
{
public:
void doSomething();
};
} // anon namespace
void myExternallyLinkedFunction()
{
++myInternallyLinkedInteger;
myInternallyLinkedFunction();
myInternallyLinkedClass x;
x.doSomething();
}
Значения статических переменных сохраняются между вызовами функций.Проверять этот Запись MSDN для примеров.Определение и использование «статических» методов описано в ответе Криша.
Статику можно использовать при реализации одноэлементных классов, где вам нужно иметь только один экземпляр класса.Его использование зависит от контекста.
В вашем примере показан шаблон «обратный вызов потока статической функции-члена».Поскольку функция потока должна иметь подпись WINAPI, она не может быть обычной функцией-членом, а только статическим членом.Часто вы передаете это как параметр потока этому обратному вызову, а затем вызываете реального участника, выполняющего работу потока.
Статический член используется только один раз, а существует множество разных.Действительно сложно догадаться, в чем цель вашего вопроса.Вы решаете какую-то конкретную проблему или вас просто интересуют все возможные варианты использования статических членов или статических функций-членов?
Более полный пример «обратного вызова потока статической функции-члена»:
class MyClass
{
/// background rendering thread
int ThreadEntry()
{
// do the work here
}
/// static member callback "proxy"
static DWORD WINAPI ThreadEntryStatic(void *param)
{
return ((EngineDD9 *)param)->ThreadEntry();
}
void SpawnThread()
{
CreateThread(.., ThreadEntryStatic, ...);
}
};