在c++中初始化私有静态数据成员的最佳方法是什么?我在头文件中尝试了这一点,但它给了我奇怪的链接器错误:
class foo
{
private:
static int i;
};
int foo::i = 0;
我猜这是因为我不能从类外部初始化一个私有成员。那么最好的方法是什么呢?
在c++中初始化私有静态数据成员的最佳方法是什么?我在头文件中尝试了这一点,但它给了我奇怪的链接器错误:
class foo
{
private:
static int i;
};
int foo::i = 0;
我猜这是因为我不能从类外部初始化一个私有成员。那么最好的方法是什么呢?
当前回答
int foo::i = 0;
是初始化变量的正确语法,但它必须放在源文件(.cpp)中,而不是放在头文件中。
因为它是一个静态变量,所以编译器只需要创建它的一个副本。你必须在你的代码中有一行"int foo:i"来告诉编译器把它放在哪里,否则你会得到一个链接错误。如果这是在一个头,你会得到一个拷贝在每个文件,包括头,所以从链接器获得多重定义的符号错误。
其他回答
类声明应该在头文件中(如果不共享,则在源文件中)。 文件:foo。
class foo
{
private:
static int i;
};
但是初始化应该在源文件中。 文件:foo.cpp
int foo::i = 0;
如果初始化是在头文件中,那么每个包含头文件的文件都有一个静态成员的定义。因此,在链接阶段,你会得到链接器错误,因为初始化变量的代码将在多个源文件中定义。 静态int i的初始化必须在任何函数之外完成。
注意:Matt Curtis:指出,如果静态成员变量是const整数类型(bool, char, char8_t[自c++ 20以来],char16_t, char32_t, wchar_t, short, int, long, long long,或任何实现定义的扩展整数类型,包括任何有符号,无符号和cv限定变量),c++允许简化上述内容。然后你可以直接在头文件的类声明中声明和初始化成员变量:
class foo
{
private:
static int const i = 42;
};
对于变量:
foo。:
class foo
{
private:
static int i;
};
foo.cpp:
int foo::i = 0;
这是因为在你的程序中只能有一个foo::i实例。它相当于头文件中的extern int i和源文件中的int i。
对于常量,你可以把值直接放在类声明中:
class foo
{
private:
static int i;
const static int a = 42;
};
对于这个问题的未来观众,我想指出您应该避免monkey0506所建议的内容。
头文件用于声明。
对于每个直接或间接包含头文件的.cpp文件,头文件将被编译一次,并且在main()之前在程序初始化时运行任何函数之外的代码。
通过输入:foo::i = VALUE;对于每个.cpp文件,foo:i将被赋值value(不管它是什么),并且这些赋值将以不确定的顺序(由链接器决定)在main()运行之前发生。
如果我们在其中一个。cpp文件中#define VALUE为不同的数字会怎样?它将编译良好,我们将无法知道哪个胜出,直到我们运行程序。
永远不要将执行的代码放入头文件中,这与您永远不要#include .cpp文件的原因相同。
Include守卫(我同意你应该经常使用)保护你不受一些不同情况的影响:在编译一个.cpp文件时,同一个头文件被间接地多次# Include。
int foo::i = 0;
是初始化变量的正确语法,但它必须放在源文件(.cpp)中,而不是放在头文件中。
因为它是一个静态变量,所以编译器只需要创建它的一个副本。你必须在你的代码中有一行"int foo:i"来告诉编译器把它放在哪里,否则你会得到一个链接错误。如果这是在一个头,你会得到一个拷贝在每个文件,包括头,所以从链接器获得多重定义的符号错误。
定义常量的一种“老派”方法是用枚举替换它们:
class foo
{
private:
enum {i = 0}; // default type = int
enum: int64_t {HUGE = 1000000000000}; // may specify another type
};
这种方法不需要提供定义,并且避免使常量为左值,这可以为您省去一些麻烦,例如当您意外地odr使用它时。