我可以在另一个函数中初始化静态成员吗?

3

struct中,有一个静态成员,因为它在析构函数中被使用。

struct Form
{
    // ...
    ~Form()
    {
        // access World here
    }
    static btDynamicsWorld *World;
};

有没有一种方法可以在另一个函数中初始化这个静态成员变量?
void ModulePhysics::Init()
{
    // ...
    btDynamicsWorld *Form::World = /* ... */;
}

我的当前代码导致了这两个编译器错误。

错误1:在当前范围内,定义或重新声明 'Form::World' 是非法的。

错误2:重新定义 'btDynamicsWorld *Form::World'。


如果这个“World”类没有直接连接到“Form”类,那么将其作为一个简单的全局变量(静态变量、命名空间或单例)可能是更好的设计。 - Sebastian
你确定只会有一个世界吗?也许你想要同时模拟两个世界……否则,你应该将世界作为Form类的普通成员,创建世界(作为模拟主函数中的普通变量),并将指向世界的指针传递给Form类的构造函数。缺点是:Form实例会消耗更多的内存。 - Sebastian
你确定必须在析构函数中从世界中移除表单吗?难道你不能在将表单从世界中移除的函数中调用析构函数吗? - Sebastian
@MichaelDorgan 我认为这是可能的。有什么优点吗?我实际上尝试过实现它,但失败了。目前我对静态成员变量的简单设置感到非常满意。 - danijar
没有技术上的优势,只是在“更好的设计”方面(例如:“我应该在World类中寻找哪个实例...在World类的某个地方!)。当您无法修改World类时,使用命名空间可能比使用World类的包装器更好。例如,在命名空间“Simulation”中。这甚至更有意义,因为从概念上讲,World实例是Simulation的一部分,而不是World类的一部分。在我看来。 - Sebastian
显示剩余11条评论
4个回答

5
不,你不能这样做。但是你可以将其初始化为 NULL,在函数中,如果它为 NULL,则进行真正的初始化。
编辑:提供一个例子:
void ModulePhysics::Init()
{
    // ...
    if(Form::World == NULL)
    {
        // The real initialization
    }
}

在某个地方,文件作用域中(在C文件中,而不是头文件中!):

btDynamicsWorld* Form::World = NULL;

那太好了,你能提供一个简短的代码示例吗? - danijar
非常感谢。现在已经编译成功了。我需要在包括这个结构体的每个源文件中初始化静态成员吗? - danijar
不行。你必须在一个文件中定义它,不能在多个文件中定义(一个定义规则,ODR)。 - Sebastian
太好了!那么这个值是在所有源文件之间共享的吗? - danijar
1
是的,它在所有源文件之间共享。不像文件范围的静态变量。 - Sebastian

2

不可以。

在类的成员列表中声明静态数据成员不是定义。你必须在命名空间范围内,在类声明之外定义静态成员。

这里提供了更详细的关于如何在哪里初始化静态类变量的描述。


0
在init()方法中,移除静态变量前面的类型声明。
希望这能解决你的问题。

我之前尝试过,但它会抛出“未解析的外部符号”链接器错误。 - danijar

0

1)所有静态类成员(除了在类定义中立即初始化的整数成员)也应该在外部定义(最好在.cpp文件中),这样编译器只会处理一次定义。例如:

// form.h
struct Form
{
    static btDynamicsWorld *World;
};


// form.cpp

// You can initialize World here as well if you want to,
// but you don't have to, as long as it's not const.
// However, it is generally a good idea to initialize
// pointers to NULL (or nullptr in C++11).
btDynamicsWorld *Form::World;

这只能在全局作用域中完成。如果您不这样做,如果您尝试引用此变量,则会收到链接器错误(未定义的符号)。

2)您似乎正在尝试做的不是“初始化”,而只是将其赋给静态成员。 您做得几乎正确,但您不需要重新声明类型:

void ModulePhysics::Init()
{
    Form::World = /* ... */;
}

3) 我真的不明白为什么你需要将任何东西设为静态来从析构函数中访问它。析构函数负责删除实例变量,但当析构函数的主体正在执行时,这些变量还没有被删除。因此,你可以使用一个“正常”的类成员,除非你计划在不同的类实例之间共享其值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接