在c++中初始化私有静态数据成员的最佳方法是什么?我在头文件中尝试了这一点,但它给了我奇怪的链接器错误:
class foo
{
private:
static int i;
};
int foo::i = 0;
我猜这是因为我不能从类外部初始化一个私有成员。那么最好的方法是什么呢?
在c++中初始化私有静态数据成员的最佳方法是什么?我在头文件中尝试了这一点,但它给了我奇怪的链接器错误:
class foo
{
private:
static int i;
};
int foo::i = 0;
我猜这是因为我不能从类外部初始化一个私有成员。那么最好的方法是什么呢?
当前回答
定义常量的一种“老派”方法是用枚举替换它们:
class foo
{
private:
enum {i = 0}; // default type = int
enum: int64_t {HUGE = 1000000000000}; // may specify another type
};
这种方法不需要提供定义,并且避免使常量为左值,这可以为您省去一些麻烦,例如当您意外地odr使用它时。
其他回答
我在这里没有足够的代表来添加这一点作为注释,但在我看来,无论如何使用#include守卫来编写头文件是一种很好的风格,正如Paranaix几小时前指出的那样,这可以防止多重定义错误。除非已经使用了单独的CPP文件,否则没有必要只使用一个文件来初始化静态的非整型成员。
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo
{
private:
static bar i;
};
bar foo::i = VALUE;
#endif
我认为没有必要为此使用单独的CPP文件。当然,你可以这样做,但是没有技术上的理由必须这样做。
使用Microsoft编译器[1],不像int型的静态变量也可以在头文件中定义,但在类声明之外,使用Microsoft特定的__declspec(selectany)。
class A
{
static B b;
}
__declspec(selectany) A::b;
请注意,我并不是说这是好的,我只是说这是可以做到的。
现在,比MSC更多的编译器支持__declspec(selectany)——至少gcc和clang。甚至更多。
我只是想提一下我第一次遇到这个的时候觉得有点奇怪的东西。
我需要在模板类中初始化一个私有静态数据成员。
在.h或.hpp中,它看起来像这样初始化模板类的静态数据成员:
template<typename T>
Type ClassName<T>::dataMemberName = initialValue;
您遇到的链接器问题可能是由以下原因引起的:
在头文件中提供类和静态成员定义, 在两个或多个源文件中包含此头文件。
对于那些从c++开始学习的人来说,这是一个常见的问题。静态类成员必须在单个翻译单元中初始化,即在单个源文件中初始化。
不幸的是,静态类成员必须在类体之外初始化。这使得只写头的代码变得复杂,因此,我使用了完全不同的方法。你可以通过静态或非静态类函数来提供你的静态对象,例如:
class Foo
{
// int& getObjectInstance() const {
static int& getObjectInstance() {
static int object;
return object;
}
void func() {
int &object = getValueInstance();
object += 5;
}
};
定义常量的一种“老派”方法是用枚举替换它们:
class foo
{
private:
enum {i = 0}; // default type = int
enum: int64_t {HUGE = 1000000000000}; // may specify another type
};
这种方法不需要提供定义,并且避免使常量为左值,这可以为您省去一些麻烦,例如当您意外地odr使用它时。