有没有什么自动化的方法来实现构造函数后和析构函数前的虚方法调用?

2021-12-23 00:00:00 methods c++ virtual-destructor

由于从构造函数和析构函数内部调用虚方法的众所周知的问题,我通常最终得到的类需要在构造函数之后调用最终设置方法,并调用预拆卸方法就在他们的析构函数之前,就像这样:

Due to the well-known issues with calling virtual methods from inside constructors and destructors, I commonly end up with classes that need a final-setup method to be called just after their constructor, and a pre-teardown method to be called just before their destructor, like this:

MyObject * obj = new MyObject;
obj->Initialize();   // virtual method call, required after ctor for (obj) to run properly
[...]
obj->AboutToDelete();  // virtual method call, required before dtor for (obj) to clean up properly
delete obj;

这是可行的,但它带来的风险是调用者会忘记在适当的时间调用这两个方法中的一个或两个.

This works, but it carries with it the risk that the caller will forget to call either or both of those methods at the appropriate times.

所以问题是:在 C++ 中有没有办法让这些方法被自动调用,所以调用者不必记住调用它们?(我猜没有,但我想我还是会问,以防万一有一些聪明的方法来做到这一点)

So the question is: Is there any way in C++ to get those methods to be called automatically, so the caller doesn't have to remember to do call them? (I'm guessing there isn't, but I thought I'd ask anyway just in case there is some clever way to do it)

推荐答案

在 C++ 中添加后构造函数的主要问题是没有人确定如何处理后后构造函数、后后构造函数等

The main problem with adding post-constructors to C++ is that nobody has yet established how to deal with post-post-constructors, post-post-post-constructors, etc.

基本理论是对象具有不变量.这个不变量是由构造函数建立的.一旦建立,就可以调用该类的方法.随着需要后构造函数的设计的引入,您正在引入这样的情况,即一旦构造函数运行,类不变量就不会建立.因此,允许从后构造函数调用虚函数同样是不安全的,并且您会立即失去它们似乎具有的一个明显好处.

The underlying theory is that objects have invariants. This invariant is established by the constructor. Once it has been established, methods of that class can be called. With the introduction of designs that would require post-constructors, you are introducing situations in which class invariants do not become established once the constructor has run. Therefore, it would be equally unsafe to allow calls to virtual functions from post-constructors, and you immediately lose the one apparent benefit they seemed to have.

如您的示例所示(可能您没有意识到),它们不是必需的:

As your example shows (probably without you realizing), they're not needed:

MyObject * obj = new MyObject;
obj->Initialize();   // virtual method call, required after ctor for (obj) to run properly

obj->AboutToDelete();  // virtual method call, required before dtor for (obj) to clean up properly
delete obj;

让我们说明为什么不需要这些方法.这两个调用可以从 MyObject 或其基础之一调用虚函数.但是,MyObject::MyObject() 也可以安全地调用这些函数.MyObject::MyObject() 返回后不会发生任何事情,这将使 obj->Initialize() 安全.所以要么obj->Initialize() 是错误的,或者它的调用可以移动到MyObject::MyObject().相同的逻辑反过来适用于 obj->AboutToDelete().最派生的析构函数将首先运行,它仍然可以调用所有虚函数,包括 AboutToDelete().

Let's show why these methods are not needed. These two calls can invoke virtual functions from MyObject or one of its bases. However, MyObject::MyObject() can safely call those functions too. There is nothing that happens after MyObject::MyObject() returns which would make obj->Initialize() safe. So either obj->Initialize() is wrong or its call can be moved to MyObject::MyObject(). The same logic applies in reverse to obj->AboutToDelete(). The most derived destructor will run first and it can still call all virtual functions, including AboutToDelete().

相关文章