在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
{
// int& getObjectInstance() const {
static int& getObjectInstance() {
static int object;
return object;
}
void func() {
int &object = getValueInstance();
object += 5;
}
};
其他回答
我在这里没有足够的代表来添加这一点作为注释,但在我看来,无论如何使用#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。甚至更多。
也在privatstatic .cpp文件中工作:
#include <iostream>
using namespace std;
class A
{
private:
static int v;
};
int A::v = 10; // possible initializing
int main()
{
A a;
//cout << A::v << endl; // no access because of private scope
return 0;
}
// g++ privateStatic.cpp -o privateStatic && ./privateStatic
int foo::i = 0;
是初始化变量的正确语法,但它必须放在源文件(.cpp)中,而不是放在头文件中。
因为它是一个静态变量,所以编译器只需要创建它的一个副本。你必须在你的代码中有一行"int foo:i"来告诉编译器把它放在哪里,否则你会得到一个链接错误。如果这是在一个头,你会得到一个拷贝在每个文件,包括头,所以从链接器获得多重定义的符号错误。
您遇到的链接器问题可能是由以下原因引起的:
在头文件中提供类和静态成员定义, 在两个或多个源文件中包含此头文件。
对于那些从c++开始学习的人来说,这是一个常见的问题。静态类成员必须在单个翻译单元中初始化,即在单个源文件中初始化。
不幸的是,静态类成员必须在类体之外初始化。这使得只写头的代码变得复杂,因此,我使用了完全不同的方法。你可以通过静态或非静态类函数来提供你的静态对象,例如:
class Foo
{
// int& getObjectInstance() const {
static int& getObjectInstance() {
static int object;
return object;
}
void func() {
int &object = getValueInstance();
object += 5;
}
};