Historia pytania
Statyczne człony klas pojawiły się w C++, aby pozwolić na przechowywanie wspólnej dla wszystkich obiektów wartości lub funkcji, nieprzypisanej do konkretnej instancji klasy. To jest wygodne dla przechowywania, na przykład, liczników, fabryk obiektów lub funkcji pomocniczych.
Problem
Jednym z problemów zawsze była widoczność i moment inicjalizacji takich członów, szczególnie jeśli w programie jest wiele plików źródłowych. Niepoprawne zdefiniowanie członu static prowadzi do błędów łączenia (linker errors).
Rozwiązanie
W C++ człony static są deklarowane w definicji klasy, ale ich inicjalizacja (dla zmiennych) musi następować oddzielnie w pliku cpp (do C++17). C++17 pozwala na inicjalizację bezpośrednio w deklaracji, jeśli jest to constexpr.
Przykład kodu:
class MyClass { public: static int counter; static void increment() { ++counter; } }; int MyClass::counter = 0; // inicjalizacja OBOWIĄZKOWA poza klasą
Kluczowe cechy:
Co się stanie, jeśli nie zdefiniujesz członu static w pliku cpp?
Otrzymasz błąd łączenia (linker error), ponieważ statyczna zmienna będzie zadeklarowana, ale nie zdefiniowana. Wyjątek — jeśli static const int jest inicjalizowany bezpośrednio w klasie dla wartości constexpr.
// .h class A { public: static int x; }; // .cpp // int A::x = 0; // jeśli zakomentowane — będzie błąd
Czy można wywołać niestatyczną funkcję z funkcji statycznej?
Nie. Funkcja statyczna nie ma dostępu do wskaźnika this i niestatycznych członów bezpośrednio. Aby uzyskać dostęp, potrzebny jest konkretny obiekt.
class B { int data; static void foo() { // data = 3; // błąd } };
Czy statyczne zmienne są wspólne dla wszystkich instancji?
Tak, w ramach jednego pliku wykonywalnego i procesu — ta sama wartość dla wszystkich instancji.
W zespole zapomniano zdefiniować człon static w pliku cpp, projekt czasami kompiluje się z błędem, a czasami, przy użyciu inicjalizacji inline (nie we wszystkich kompilatorach), pojawia się "tajemniczy" błąd wykonania.
Zalety:
Wady:
W firmie ustalono zasadę: człony static są zawsze definiowane w plikach cpp dla każdej klasy. Dla bezpieczeństwa wątków używane są std::mutex lub operacje atomowe.
Zalety:
Wady: