是否有任何自动化方法来实现构造函数后和析构函数前的虚拟方法调用?
由于从构造函数和析构函数内部调用虚拟方法存在众所周知的问题,我通常会得到这样的类,这些类需要在其构造函数之后调用最终设置方法,并在其构造函数之前调用预拆卸方法。析构函数,如下所示:
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;
这可行,但它带来了调用者忘记在适当的时间调用其中一个或两个方法的风险。
所以问题是:C++ 中是否有任何方法可以自动调用这些方法,以便调用者不必记住调用它们? (我猜没有,但我想我还是会问,以防万一有一些聪明的方法可以做到这一点)
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.
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
虽然没有自动化的方法,但您可以通过拒绝用户访问该类型的析构函数并声明特殊的删除方法来强制用户进行操作。 通过这种方法,您可以进行您想要的虚拟呼叫。 创建可以采用与静态工厂方法类似的方法。
现在无法调用“delete obj;” 除非调用站点有权访问 MyObject 私有成员。
While there is no automated way, you could force the users hand by denying users access to the destructor on that type and declaring a special delete method. In this method you could do the virtual calls you'd like. Creation can take a similar approach which a static factory method.
Now it is not possible to call "delete obj;" unless the call site has access to MyObject private members.
我能想到的最好的方法是使用静态 Create 方法实现自己的智能指针,该方法更新实例并调用 Initialize,并在其析构函数中调用 AboutToDelete,然后删除。
The best I can think of is for you to implement your own smart pointer with a static Create method that news up an instance and calls Initialize, and in its destructor calls AboutToDelete and then delete.
我使用了一个非常精心设计的 Create() 工厂方法(每个类的静态成员),以与 C# 初始化类型相同的顺序调用构造函数和初始化程序对。 它返回一个
shared_ptr
到该类型的实例,保证堆分配。 随着时间的推移,它被证明是可靠且一致的。窍门:我从 XML 生成了 C++ 类声明...
I used a very carefully designed
Create()
factory method (static member of each class) to call a constructor and initializer pair in the same order as C# initializes types. It returned ashared_ptr
to an instance of the type, guaranteeing a heap allocation. It proved reliable and consistent over time.The trick: I generated my C++ class declarations from XML...
除了 JavedPar 的预销毁方法的想法之外,没有任何预制的解决方案可以在 C++ 中轻松地进行两阶段构造/销毁。 最明显的方法是遵循 C++ 中问题的最常见答案:“添加另一层间接层”。
您可以将此类层次结构的对象包装在另一个对象中。 然后该对象的构造函数/析构函数可以调用这些方法。 例如,查看 Couplien 的 letter-envelop 习语,或者使用已经建议的智能指针方法。
Except for JavedPar's idea for the pre-destruction method, there is no pre-made solution to easily do two-phase construction/destruction in C++. The most obvious way to do this is to follow the Most Common Answer To Problems In C++: "Add another layer of indirection."
You can wrap objects of this class hierarchy within another object. That object's constructors/destructor could then call these methods. Look into Couplien's letter-envelop idiom, for example, or use the smart pointer approach already suggested.
http://www.research.att.com/~bs/wrapper.pdf< /a> Stroustrup 的这篇论文将解决您的问题。
我在 VS 2008 和 UBUNTU 上针对 g++ 编译器对此进行了测试。 效果很好。
http://www.research.att.com/~bs/wrapper.pdf This paper from Stroustrup will solve your problem.
I tested this under VS 2008 and on UBUNTU against g++ compiler. It worked fine.
您可以在类中使用静态函数模板。 与私人医生/医生。
在vs2015社区上运行
You can use static function template in the class. With private ctor/dtor.
Run on vs2015 community
我遇到了同样的问题,经过一番研究,我相信没有任何标准的解决方案。
我最喜欢的建议是 Aleksandrescu 等人提供的建议。 书“C++ 编码标准”中的第 49 项。
引用它们(合理使用),您有多种选择:
详情请参阅他的书。
I was stuck with the same problem, and after a bit of research, I believe there is not any standard solution.
The suggestions that I liked most are the ones provided in the Aleksandrescu et al. book "C++ coding standards" in the item 49.
Quoting them (fair use), you have several options:
See his book for details.
在 C++ 中添加后构造函数的主要问题是,还没有人确定如何处理后后构造函数、后后构造函数等。
其基本理论是对象具有不变量。 这个不变量是由构造函数建立的。 一旦建立,就可以调用该类的方法。 随着需要后构造函数的设计的引入,您正在引入这样的情况:一旦构造函数运行,类不变量就不会建立。 因此,允许从后构造函数调用虚拟函数同样不安全,并且您立即失去了它们似乎拥有的一项明显的好处。
正如您的示例所示(可能您没有意识到),不需要它们:
让我们展示为什么不需要这些方法。 这两个调用可以从
MyObject
或其基础之一调用虚拟函数。 但是,MyObject::MyObject()
也可以安全地调用这些函数。MyObject::MyObject()
返回后不会发生任何使obj->Initialize()
安全的事情。 因此,要么obj->Initialize()
是错误的,或者可以将其调用移至MyObject::MyObject()
。 同样的逻辑反过来也适用于obj->AboutToDelete()
。 最派生的析构函数将首先运行,它仍然可以调用所有虚拟函数,包括AboutToDelete()
。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:
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 afterMyObject::MyObject()
returns which would makeobj->Initialize()
safe. So eitherobj->Initialize()
is wrong or its call can be moved toMyObject::MyObject()
. The same logic applies in reverse toobj->AboutToDelete()
. The most derived destructor will run first and it can still call all virtual functions, includingAboutToDelete()
.我在施工时遇到了同样的问题。 这是我使用 C++14 的解决方案。
这个想法是在与最终对象的声明相同(或非常接近)的范围内声明类
Call
的实例,让析构函数调用创建后脚本。I had the same problem for construction. This is my solution using C++14.
The idea is to declare an instance of the class
Call
in the same (or quite close) scope than the declaration of the final object, letting the destructor call the post-creation script.还没有看到答案,但基类只是在类层次结构中添加代码的一种方法。 您还可以创建旨在添加到层次结构另一侧的类:
Haven't seen the answer yet, but base classes are only one way to add code in a class hierarchy. You can also create classes designed to be added to the other side of the hierarchy: