我应该使用虚拟的“Initialize()"函数来初始化我的类的对象吗?

2022-01-18 00:00:00 initialization c++

我目前正在与我的老师讨论班级设计,我们谈到了他大力推广的 Initialize() 函数.示例:

I'm currently having a discussion with my teacher about class design and we came to the point of Initialize() functions, which he heavily promotes. Example:

class Foo{
public:
  Foo()
  { // acquire light-weight resources only / default initialize
  }

  virtual void Initialize()
  { // do allocation, acquire heavy-weight resources, load data from disk
  }

  // optionally provide a Destroy() function
  // virtual void Destroy(){ /*...*/ }
};

当然,一切都带有可选参数.

Everything with optional parameters of course.

现在,他还强调类层次结构中的可扩展性和使用(他是一名游戏开发人员,他的公司销售游戏引擎),并提出以下论点(逐字记录,仅翻译):

Now, he also puts emphasis on extendability and usage in class hierarchies (he's a game developer and his company sells a game engine), with the following arguments (taken verbatim, only translated):

反对构造函数的论点:

  • 不能被派生类覆盖
  • 无法调用虚函数

Initialize() 函数的参数:

  • 派生类可以完全替代初始化代码
  • 派生类可以在自己的初始化过程中随时进行基类初始化

我一直被教导直接在构造函数中进行真正的初始化,并且不提供这样的Initialize()函数.也就是说,在部署库/引擎方面,我肯定没有他那么多的经验,所以我想我会问好.

I have always been taught to do the real initialization directly in the constructor and to not provide such Initialize() functions. That said, I for sure don't have as much experience as he does when it comes to deploying a library / engine, so I thought I'd ask at good ol' SO.

那么,支持和反对这种 Initialize() 函数的论据究竟是什么?它是否取决于它应该使用的环境?如果是,请为库/引擎开发人员提供推理,或者,如果可以,甚至是一般的游戏开发人员.

So, what exactly are the arguments for and against such Initialize() functions? Does it depend on the environment where it should be used? If yes, please provide reasonings for library / engine developers or, if you can, even game developer in general.

编辑:我应该提到,这些类将仅用作其他类中的成员变量,因为其他任何东西对它们都没有意义.对不起.

Edit: I should have mentioned, that such classes will be used as member variables in other classes only, as anything else wouldn't make sense for them. Sorry.

推荐答案

对于 Initialize:正如你的老师所说的那样,但在精心设计的代码中你可能永远不需要它.

For Initialize: exactly what your teacher says, but in well-designed code you'll probably never need it.

反对:非标准,如果被虚假使用,可能会破坏构造函数的目的.更重要的是:客户端需要记住调用Initialize.因此,要么实例在构造时处于不一致状态,要么它们需要大量额外的簿记以防止客户端代码调用其他任何东西:

Against: non-standard, may defeat the purpose of a constructor if used spuriously. More importantly: client needs to remember to call Initialize. So, either instances will be in an inconsistent state upon construction, or they need lots of extra bookkeeping to prevent client code from calling anything else:

void Foo::im_a_method()
{
    if (!fully_initialized)
        throw Unitialized("Foo::im_a_method called before Initialize");
    // do actual work
}

防止这种代码的唯一方法是开始使用工厂函数.因此,如果您在每个类中都使用 Initialize,则每个层次结构都需要一个工厂.

The only way to prevent this kind of code is to start using factory functions. So, if you use Initialize in every class, you'll need a factory for every hierarchy.

换句话说:如果没有必要,不要这样做;始终检查是否可以根据标准结构重新设计代码.当然不要添加 public Destroy 成员,这是析构函数的任务.析构函数可以(并且在继承的情况下,必须)是virtual.

In other words: don't do this if it's not necessary; always check if the code can be redesigned in terms of standard constructs. And certainly don't add a public Destroy member, that's the destructor's task. Destructors can (and in inheritance situations, must) be virtual anyway.

相关文章