从标记为final的类的构造函数调用虚函数是不好的做法

mar*_*ark 17 c++ constructor virtual-functions dynamictype c++11

通常从构造函数调用虚函数被认为是不好的做法,因为子对象中的被覆盖函数将不会被调用,因为尚未构造对象.

但是,请考虑以下类:

class base
{
public:
   base() {}
   ~base() {}

private:
   virtual void startFSM() = 0;
};

class derived final : public base
                    , public fsm_action_interface
{
public:
    derived() : base{}
              , theFSM_{}
    {  startFSM(); }


    /// FSM interface actions

private:
   virtual void startFSM()
   { theFSM_.start(); }

private:
    SomeFSMType theFSM_;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,类derived被标记为,final因此不存在其他子对象.因此,虚拟调用将正确解析(到最派生类型).

它仍然被认为是不好的做法吗?

bst*_*r55 9

这仍然被认为是不好的做法,因为这种情况几乎总是表明设计不好.您必须对代码中的内容进行评论,以解释为什么这种情况适用于这种情况.

TC上面的评论强调了为什么这被认为是不良做法的原因之一.

如果,在一年之后,你决定派生不应该是最终的,那么会发生什么?

也就是说,在上面的例子中,模式可以正常工作.这是因为派生类型最多的构造函数是调用虚函数的构造函数.当基类的构造函数调用解析为子类型实现的虚函数时,此问题就会出现.在C++中,不会调用这样的函数,因为在基类构造期间,此类调用永远不会转到比当前正在执行的构造函数或析构函数更多的派生类.从本质上讲,你最终会得到你没想到的行为.

编辑:

所有(正确/非错误)C++实现必须调用在当前构造函数中的层次结构级别定义的函数的版本,而不再进一步调用.

C++ FAQ精简版包括这在相当不错的细节部分23.7.

Scott Meyers还讨论了在Effective C++ Item 9中从构造函数和析构函数调用虚函数的一般问题


Che*_*Alf 8

关于

"通常从构造函数调用虚函数被认为是不好的做法,因为子对象中的被覆盖函数将不会被调用,因为尚未构造对象.

事实并非如此.在有能力的C++程序员中,从构造函数调用虚函数(除了纯虚函数)通常不被视为不好的做法,因为C++ 旨在很好地处理它.与Java和C#等语言相比,它可能导致在尚未初始化的派生类子对象上调用方法.

请注意,动态类型的动态调整具有运行时成本.

在一种面向最终效率的语言中,"你不用你不用的东西"作为一个主要的指导原则,这意味着它是一个重要且非常有意的特征,而不是任意选择.它仅用于一个目的.即支持这些电话.


关于

"在这种情况下,派生类被标记为final,因此不存在其他子对象.因此,虚拟调用将正确解析(到最派生类型).

C++标准保证在施工执行的一类时间Ť,动态类型是Ť.

因此,首先解决不正确的类型没有问题.


关于

"它仍被视为不良做法吗?

virtualfinal类中声明成员函数确实是不好的做法,因为这没有意义. "静止"并不是很有意义 无论是.

对不起,我没有看到虚拟成员函数是这样继承的.

将成员函数标记为纯虚拟的覆盖或实现的最佳实践是使用关键字override,而不是将其标记为virtual.

从而:

void startFSM() override
{ theFSM_.start(); }
Run Code Online (Sandbox Code Playgroud)

如果它不是覆盖/实现,这可以确保编译错误.

  • 我不同意.请参阅_Item 9:从未在构建过程中调用虚函数或在_Effective C++中调用destroy_作者:Scott Meyers,以及_Item 49:避免在Herb Sutter和Andrei Alexandrescu的_C++编码标准中调用构造函数和析构函数中的虚函数. (6认同)
  • @nosid:这听起来像权威论点.我多次不同意斯科特和安德烈的观点.有时他们同意我,有时候不同意.为什么不引用你发现令人信服的理由. (4认同)
  • 这在技术上都是正确的,但在我看来,它并没有解决这里的根本问题:"为什么你在一个特定地抑制调用的多态方面的上下文中调用虚方法?".这是一种强烈的设计气味,在许多情况下可以以另一种方式解决. (2认同)