This is quite complicated, and I had to edit the message several times (thanks to the guys who helped me), I will try to make it simple and refer to the N3690:
§12.7.4 conditions
Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2).
and this is what you did in constructor B
B::B() { b.foo(); // virtual foo(); // virtual }
This is completely legal. This pointer (implicitly used in the second function call) always points to the constructed object.
Then the standard also says:
When a virtual function is called directly or indirectly from the constructor and the object to which the call is applied, if the object (call it x) is under construction or destruction, the called function is the final redirector in the class of constructors or destructors and does not redefine it in a more derived class (such ignore more derived versions of the function)
so the vtable didn’t completely go through, as you might think, but settled on the version of the virtual function of the constructor class (see http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from- ctors.html ).
Still legal.
Finally, to your point:
If calling a virtual function uses explicit access to a class member, for example. (object.vfunction () or object-> vfunction ()), and the expression of the object refers to the full object x or one of the subobjects of the base class of objects, but not to x or one of its subobjects of the base class (i.e. not to the object , construction or one of its subobjects of the base class), undefined behavior.
To understand this sentence, we first need to understand what the full object x means:
§1.8.2
Objects may contain other objects called subobjects. A subobject can be a member subobject (9.2), a base subclass of a class object (section 10), or an array element. An object that is not a subobject of any other object is called a complete object.
For each object x, there is some object called the complete object x, defined as follows:
- If x is a complete object, then x is a complete object x.
- Otherwise, the complete object x is the complete object of the (unique) object that contains x
if you combine the previous previous pass, you will get that you cannot call a virtual function that refers to the "full type" of the base class (that is, a derived object that is not yet constructed) or the object that owns this element of the element or array.
If you must explicitly reference the C in B constructor:
B::B() { static_cast<C*>(this)->foo();
then you would have undefined behavior.
The intuitive (more or less) reason is that
A virtual or member function call is allowed in the constructor, and in the case of virtual functions, it “stops the virtual hierarchy” before this object and calls its version of the function (see http://www.parashift.com/c%2B%2B-faq-lite /calling-virtuals-from-ctors.html )
In any case, if you do this from a subobject referencing the full object of that subobject (re-read the standard pass), then it has undefined behavior
Practical use: Do not call virtual functions in your constructors / destructors unless you are sure you can .
If I have something wrong, please let me know in the comments below and I will correct the message. Thanks!