Call a virtual function inside the constructor using an object-expression

前端 未结 2 1981
借酒劲吻你
借酒劲吻你 2021-01-13 05:44

Code:

#include 

using std::cout;
using std::endl;

struct A
{
    virtual void foo()
    {
        cout << \"A\" << endl;
    }
         


        
2条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-13 05:58

    §1.8 [intro.object]/p2-3:

    Objects can contain other objects, called subobjects. A subobject can be a member subobject (9.2), a base class subobject (Clause 10), or an array element. An object that is not a subobject of any other object is called a complete object.

    For every object x, there is some object called the complete object of x, determined as follows:

    • If x is a complete object, then x is the complete object of x.
    • Otherwise, the complete object of x is the complete object of the (unique) object that contains x.

    In essence, the sentence you cited makes doing static_cast(this)->foo(); in B's constructor undefined behavior in your code, even if the complete object being constructed is a C. The standard actually provides a pretty good example here:

    struct V {
        virtual void f();
        virtual void g();
    };
    struct A : virtual V {
        virtual void f();
    };
    struct B : virtual V {
        virtual void g();
        B(V*, A*);
    };
    
    struct D : A, B {
        virtual void f();
        virtual void g();
        D() : B((A*)this, this) { }
    };
    
    B::B(V* v, A* a) {
        f();    // calls V::f, not A::f
        g();    // calls B::g, not D::g
        v->g(); // v is base of B, the call is well-defined, calls B::g
        a->f(); // undefined behavior, a’s type not a base of B
    }
    

    In fact, you can already see the undefined behavior show up in this example if you run it: Ideone's compiler (GCC) actually calls V::f() on the a->f(); line, even though the pointer is referring to a fully constructed A subobject.

提交回复
热议问题