在C++编程中,静态数据成员的使用非常普遍,它们为所有类实例提供了单一的数据副本,而不是每个对象都拥有一份拷贝。然而,随着静态数据成员的复杂度增加,C++语言的限制也变得明显。静态数据成员必须在类体外初始化,通常在.cpp文件中,除了const整型静态数据成员之外。这对于在单一.h文件中定义的内联类和模板来说是一个很大的不便。
C++没有像Java或C#那样的静态构造函数,因此通常需要逐个初始化静态数据成员。这限制了不能在同一个循环或算法中初始化多个静态数据成员。为了解决这些限制,提出了一种解决方案。
在Stack Overflow上讨论了第一个限制:。关于第二个限制,可以阅读这个话题:。观点是,尽管C++最初没有静态构造函数,但扩展语言以像Java和C#那样工作是有趣的,因为程序员可以自由选择是否使用它。
使用代码的方法非常简单:包括提供的StaticConstructor.h文件。声明StaticConstructor和StaticDestructor作为类的静态函数成员。在类体外使用宏调用它们。
#include "StaticConstructor.h"
class MyClass {
protected:
// 在这里声明静态和非静态数据成员...
public:
// 默认构造函数:
MyClass() {
// 在这里对非静态数据成员进行一些操作...
}
// 析构函数:
virtual ~MyClass() {
// 在这里对非静态数据成员进行一些操作...
}
// 静态构造函数:
// (应由INVOKE_STATIC_CONSTRUCTOR宏调用)
static void StaticConstructor() {
// 在这里对静态数据成员进行一些操作...
}
// 静态析构函数:
// (应由INVOKE_STATIC_CONSTRUCTOR宏调用)
static void StaticDestructor() {
// 在这里对静态数据成员进行一些操作...
}
};
// 调用类的StaticConstructor & StaticDestructor:
// 确保将此放在静态数据成员初始化之后!
INVOKE_STATIC_CONSTRUCTOR(MyClass);
在模板中使用这种静态构造函数是可能的,但重要的是要分别调用每个模板实例的静态构造函数。
// 模板实例的别名声明:
typedef MyTemplate MyTemplateInt;
typedef MyTemplate MyTemplateDouble;
// 调用每个模板实例的StaticConstructor & StaticDestructor:
// 应使用别名(类名)调用.
INVOKE_STATIC_CONSTRUCTOR(MyTemplateInt);
INVOKE_STATIC_CONSTRUCTOR(MyTemplateDouble);
在C++中,不能在静态构造函数中初始化数据成员,因此尝试了一种变通方法。而不是使用数据成员,使用了一个函数成员来存储数据。称之为“数据函数成员”(DF成员),其实现如下:
static TypeName& DFMemberName() {
static TypeName DFMemberName(InitValue);
return DFMemberName;
}
在示例中,使用宏STATIC_DF_MEMBER(TypeName, DFMemberName, InitValue)以更简单的方式声明它们。可以在类或模板头声明中声明DF成员,并在静态构造函数和静态析构函数中访问它们。可以将它们用作数据成员的引用(实际上,它们是返回数据的函数成员),因此这种代码是有效的:
DFMemberName() = Value2;
DF成员在第一次访问时初始化,而不是在声明时初始化(它们不是普通数据成员),所以可能希望在静态构造函数中访问它们,以确保它们在执行开始时初始化。
在使用调用静态构造函数的宏的技巧中声明了一个全局变量(将在启动时构造),以在其默认构造函数中放置一些代码(对类的静态构造函数的调用)。该类的析构函数将调用类的静态析构函数。