【发布时间】:2015-06-03 21:54:57
【问题描述】:
我想知道对于必须具有相对较大范围/较长生命周期的对象而言,进行对象初始化和存储的最佳方法是什么。假设我们有一个GameEngine 类,它需要初始化并保存对Window 的引用以进行渲染。在程序的整个生命周期中都需要引用,并且窗口至少需要知道它的尺寸。
在 Java 中,我会这样做:
// Declaration:
Window window;
// Initialization:
window = new Window(width, height);
我知道在 C++ 中,第一个已经调用了 Window 类的默认构造函数,因此是 declaration 和 initialization。因此,拥有window = Window(width, height); 将是assignment,丢弃已经存在的对象。
我能找到的第一个解决方案是使用指针:
// GameEngine.hpp
class GameEngine {
Window *window;
};
// Somewhere in GameEngine.cpp:
window = new Window(width, height);
但话又说回来,我经常读到一个应该尽可能偏爱普通对象而不是指针,事实上,我很快就让自己陷入了一堆乱七八糟的指针,所以我正在寻找另一种方法。
另一种解决方案似乎将您的对象设计为具有不带参数的构造函数并稍后设置对象:
// GameEngine.hpp
class GameEngine {
Window window;
};
// Somewhere in GameEngine.cpp
window.setWidth(width);
window.setHeight(height);
这可行,但有一个严重的缺点:对象(至少在这种情况下)可能处于不一致的状态,因为在不设置宽度/高度的情况下尝试显示窗口会导致错误或崩溃。它对某些对象有效,但对大多数对象无效。
避免这种情况的一种方法是使用默认值。例如,Window 类的构造函数可能如下所示:
Window::Window(int width = 800, int height = 600) {}
甚至是这样:
Window::Window() : width(DEFAULT_WIDTH), height(DEFAULT_HEIGHT) {}
但在很多情况下,默认值很难确定。另外,他们应该从哪里来? Window 类是否应该定义DEFAULT_WIDTH 和DEFAULT_HEIGHT? 或者我应该这样做吗?
// GameEngine.hpp
class GameEngine {
static const int DEFAULT_WIDTH = 800;
static const int DEFAULT_HEIGHT = 600;
Window window(800,600);
};
但这似乎很糟糕,因为我已经读过您不应该在标头中进行任何初始化,只能在声明中进行,因此此时实际上不应该知道 DEFAULT_WIDTH 和 DEFAULT_HEIGHT 的值(并且只能在 .cpp 中初始化,对吗?)。
我错过了一个选项吗? 或者在 C++ 中是否普遍假设程序员应该知道自己在做什么,并在使用对象之前确保对象处于一致状态? 何时使用哪种方法?
【问题讨论】:
-
@close 投票 - 对我来说,这看起来不像是基于意见的问题。虽然措辞有点糟糕(可能是由于缺乏理解),但问题实际上是关于 C++ 语言的技术问题。
-
我认为它是在询问如何进行两阶段初始化
-
我觉得我错过了什么;为什么不能同时创建 Window 对象并对其进行初始化是有原因的吗?你需要声明和初始化在不同的地方吗?因为如果你不这样做,那么只需在声明语句中包含初始化就没有问题。
-
@MattMcNabb 呵呵。我认为问题是关于如何避免进行两阶段初始化。
-
@domdom 两阶段初始化意味着你在构建的时候初始化一些东西,然后再初始化一些东西。您正在描述初始化然后分配,这是实现两阶段的一种方式;但不是唯一的方法。我的回答显示了另一种不涉及分配的方式。这个问题没有单一的正确答案,这是一个通常基于经验的设计决定!所以我建议只是做一些事情,然后你会通过看看你的项目结果来了解它的利弊。
标签: c++ pointers object initialization declaration