在c++中初始化私有静态数据成员的最佳方法是什么?我在头文件中尝试了这一点,但它给了我奇怪的链接器错误:
class foo
{
private:
static int i;
};
int foo::i = 0;
我猜这是因为我不能从类外部初始化一个私有成员。那么最好的方法是什么呢?
在c++中初始化私有静态数据成员的最佳方法是什么?我在头文件中尝试了这一点,但它给了我奇怪的链接器错误:
class foo
{
private:
static int i;
};
int foo::i = 0;
我猜这是因为我不能从类外部初始化一个私有成员。那么最好的方法是什么呢?
当前回答
如果使用头保护,也可以在头文件中包含赋值。我在自己创建的c++库中使用了这种技术。实现相同结果的另一种方法是使用静态方法。例如……
class Foo
{
public:
int GetMyStatic() const
{
return *MyStatic();
}
private:
static int* MyStatic()
{
static int mStatic = 0;
return &mStatic;
}
}
上面的代码有一个“好处”,就是不需要CPP/源文件。同样,这是我在c++库中使用的方法。
其他回答
我遵循卡尔的想法。我喜欢它,现在我也在用它。 我稍微改变了一下符号,增加了一些功能
#include <stdio.h>
class Foo
{
public:
int GetMyStaticValue () const { return MyStatic(); }
int & GetMyStaticVar () { return MyStatic(); }
static bool isMyStatic (int & num) { return & num == & MyStatic(); }
private:
static int & MyStatic ()
{
static int mStatic = 7;
return mStatic;
}
};
int main (int, char **)
{
Foo obj;
printf ("mystatic value %d\n", obj.GetMyStaticValue());
obj.GetMyStaticVar () = 3;
printf ("mystatic value %d\n", obj.GetMyStaticValue());
int valMyS = obj.GetMyStaticVar ();
int & iPtr1 = obj.GetMyStaticVar ();
int & iPtr2 = valMyS;
printf ("is my static %d %d\n", Foo::isMyStatic(iPtr1), Foo::isMyStatic(iPtr2));
}
这个输出
mystatic value 7
mystatic value 3
is my static 1 0
如果使用头保护,也可以在头文件中包含赋值。我在自己创建的c++库中使用了这种技术。实现相同结果的另一种方法是使用静态方法。例如……
class Foo
{
public:
int GetMyStatic() const
{
return *MyStatic();
}
private:
static int* MyStatic()
{
static int mStatic = 0;
return &mStatic;
}
}
上面的代码有一个“好处”,就是不需要CPP/源文件。同样,这是我在c++库中使用的方法。
对于这个问题的未来观众,我想指出您应该避免monkey0506所建议的内容。
头文件用于声明。
对于每个直接或间接包含头文件的.cpp文件,头文件将被编译一次,并且在main()之前在程序初始化时运行任何函数之外的代码。
通过输入:foo::i = VALUE;对于每个.cpp文件,foo:i将被赋值value(不管它是什么),并且这些赋值将以不确定的顺序(由链接器决定)在main()运行之前发生。
如果我们在其中一个。cpp文件中#define VALUE为不同的数字会怎样?它将编译良好,我们将无法知道哪个胜出,直到我们运行程序。
永远不要将执行的代码放入头文件中,这与您永远不要#include .cpp文件的原因相同。
Include守卫(我同意你应该经常使用)保护你不受一些不同情况的影响:在编译一个.cpp文件时,同一个头文件被间接地多次# Include。
如果你想初始化一些复合类型(f.e. string),你可以这样做:
class SomeClass {
static std::list<string> _list;
public:
static const std::list<string>& getList() {
struct Initializer {
Initializer() {
// Here you may want to put mutex
_list.push_back("FIRST");
_list.push_back("SECOND");
....
}
}
static Initializer ListInitializationGuard;
return _list;
}
};
由于ListInitializationGuard是SomeClass::getList()方法中的一个静态变量,它将只被构造一次,这意味着构造函数被调用一次。这将初始化_list变量为你需要的值。任何后续对getList的调用都将返回已经初始化的_list对象。
当然,您必须始终通过调用getList()方法访问_list对象。
定义常量的一种“老派”方法是用枚举替换它们:
class foo
{
private:
enum {i = 0}; // default type = int
enum: int64_t {HUGE = 1000000000000}; // may specify another type
};
这种方法不需要提供定义,并且避免使常量为左值,这可以为您省去一些麻烦,例如当您意外地odr使用它时。