问题的历史
静态类成员出现在C++中,以便存储所有对象共享的值或不与特定类实例绑定的函数。这在存储例如计数器、工厂对象或辅助函数时非常方便。
问题
一个复杂的问题一直是这些成员的作用域和初始化时机,尤其是在程序中有很多源文件时。不正确的静态成员定义会导致链接错误(linker errors)。
解决方案
在C++中,静态成员在类定义中声明,但它们的初始化(对于变量)必须在cpp文件中单独进行(在C++17之前)。C++17允许在声明内部初始化,如果这是constexpr。
代码示例:
class MyClass { public: static int counter; static void increment() { ++counter; } }; int MyClass::counter = 0; // 在类外部初始化是必须的
关键特点:
如果不在cpp文件中定义静态成员会发生什么?
将会得到链接错误(linker error),因为静态变量将会声明但未定义。例外情况是,如果static const int直接在类内部初始化为constexpr值。
// .h class A { public: static int x; }; // .cpp // int A::x = 0; // 如果被注释掉 — 会出现错误
可以从静态函数中调用非静态函数吗?
不能。静态函数无法直接访问this指针和非静态成员。需要具体的对象才能访问。
class B { int data; static void foo() { // data = 3; // 错误 } };
静态变量对于所有实例是共享的吗?
是的,在同一个可执行文件和进程范围内 — 所有实例共享同一个值。
在团队中忘记在cpp文件中定义静态成员,项目偶尔会出现编译错误,有时在使用内联初始化时(并非所有编译器都支持),会出现“神秘的”运行时错误。
优点:
缺点:
公司制定了一个规则:每个类的静态成员总是在cpp文件中定义。为线程安全使用std::mutex或原子操作。
优点:
缺点: