If a virtual function is called from a constructor / destructor without qualification, is there a virtual dispatch?

struct A { virtual ~A() { f(); } virtual void f() {} }; 

I clarified my question to be more specific.

In this code example, MAY use the f() call using virtual send, or will it be equivalent to A::f() ?

Could you provide an appropriate section from the C ++ standard? Thanks.

+4
source share
4 answers

Inside the constructor or destructor, the subclass object has either not yet been constructed or has already been destroyed. As a result, virtual dispatch does not lead to the use of the used version of the derived class, and instead the base class version is called.

From the standard [class.cdtor]/4 :

Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor or from a destructor, including when constructing or destroying non-static elements of these classes, and the object to which the call is applied is the object (name it x) for construction or destruction, the called function is the final redirect in the class of constructors or destructors, and not the one that overrides it in a more derived class. If the call to the virtual function uses an explicit class member (5.2.5), and the expression of the object refers to the full object x or to one of these subobjects of the base class of objects, but not to x or one of its subobjects of the base class, the behavior is undefined.

An example is given:

 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 } 

Also note that this may be unsafe if the called function is pure virtual, from [class.abstract]/6 :

Member functions can be called from the constructor (or destructor) of an abstract class; the effect of a virtual call (10.3) on a pure virtual function, directly or indirectly, for a created (or destroyed) object from such a constructor (or destructor) is undefined.

+7
source

The standard does not require a call to be made dynamically or statically. Conceptually, this is dynamic, and all quotes regarding the invocation of a virtual function when constructing or destroying an object contain text directly or indirectly. This is important because it entails whether the call is direct to the function or not, should be the same thing. Now consider:

 struct A { A() { f(); } void f() { g(); } virtual void g() {}; }; 

And suppose the code is not displayed and all the usual caveats are so that functions are not included. The definition of A::f() , which may be in another translation unit, does not know whether it is called from the constructor or destructor, or with none of them. He does not know if the complete object has type A or Z for any derived type Z , so he must use dynamic dispatch.

Now the as-if rule means that the compiler has some freedom of action for optimization, and it can decide that in the body of the constructor / destructor (or any function built into it) the final override is known, and it can thus avoid dynamic dispatch and immediately call the known final override. This works even for pure virtual functions, because in this case the behavior is undefined, and therefore there is no guarantee of behavior - therefore, any conversion by the compiler will be in this case.

+2
source

§12.7.4:

Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor or from a destructor, including when building or destroying non-static elements of these classes, and the object to which the call is applied is an object (name it x) for construction or destruction, the called function is the final redistribution in the class of constructors or destructors, and does not override it in a more derived class.

§10.4.6:

Member functions can be called from the constructor (or destructor) of an abstract class; the effect of a virtual call (10.3) on a pure virtual function, directly or indirectly, for a created (or destroyed) object from such a constructor (or destructor) is undefined.

The virtual dispatch occurs, and the function called is the last override in the class chain until it is created. If the function has never been implemented, the behavior is undefined.

 // well-defined behavior, calls A::f() struct A { A() { f(); } virtual void f(); }; struct B { virtual void f(); }; // well-defined behavior, calls B::f() struct C : public B { C() { f(); } }; // well-defined behavior, calls D::f() struct D : public B { D() { f(); } virtual void f(); }; // calling a pure virtual method from a constructor: undefined behavior // (even if D::f() is implemented at a later point) struct D { D() { f(); } virtual void f() = 0; }; // specifying f() as pure virtual even if it has an implementation in B, // then calling it from the constructor: undefined behavior struct E : public B { E() { f(); } virtual void f() = 0; }; 
0
source

Yes. Any unqualified reference to a member from his class is fully equivalent

 this->member 

or

 this->member(...) 

if necessary, and actually sent virtually, if it is a virtual function. The standard does not make any exceptions about calls from constructors or destructors. He makes an exception from which the function is called, but not about how this is done.

EDIT

The actual VFT mechanism used to implement this exception is described in [1]. As Lippman points out, simply erasing a virtual despot is not an acceptable method, since any indirect invocation of a virtual function called by the called virtual function is also subject to the same exception ("directly or indirectly").

 [1] Lippman, Stanley B., *Inside the C++ Object Model,* Addison Wesley 1996, pp179ff. 
-3
source

Source: https://habr.com/ru/post/952562/


All Articles