13 November 2022

C++ 核心指南目录

C.82: Don’t call virtual functions in constructors and destructors

理由

构造函数和析构函数中调用的函数应该是当前正在构造的对象的函数,而不应该是继承类中需要重载的虚函数。不然会让人很难理解。

更差的情况,在构造或析构函数中,直接或间接调用还没实现的纯虚函数会产生未定义的行为。

例子

class Base {
public:
    virtual void f() = 0;   // not implemented
    virtual void g();       // implemented with Base version
    virtual void h();       // implemented with Base version
    virtual ~Base();        // implemented with Base version
};

class Derived : public Base {
public:
    void g() override;   // provide Derived implementation
    void h() final;      // provide Derived implementation

    Derived()
    {
        // BAD: attempt to call an unimplemented virtual function
        f();

        // BAD: will call Derived::g, not dispatch further virtually
        g();

        // GOOD: explicitly state intent to call only the visible version
        Derived::g();

        // ok, no qualification needed, h is final
        h();
    }
};

注意

调用一个明确限定了从属于哪个类的函数,就算这个函数是个虚函数,也已经不是虚调用了。

请查看C.50工厂函数,如何调用继承类的函数而不会导致未定义行为结果。

注意

在构造函数和析构函数中调用虚函数没有什么内在错误。语义上来说这种调用是类型安全的。但是,经验表明这种调用不太需要、容易混淆维护者、成为信手的错误之源。

强化

  • 标记在构造和析构函数中调用虚函数的情况