9
votes

I know that for any class that has a virtual function or a class that is derived from a class that has a virtual function, the compiler does two things. First, it creates a virtual table for that class and secondly, it puts a virtual pointer (vptr) in the base portion for the object. During runtime, this vptr gets assigned and starts pointing to the correct vtable when the object gets instantiated.

My question is that where exactly in the instantiation process does this vptr gets set? Does this assignment of vptr happens inside the constructor of the object of before/after the constructor?

5
It's entirely implementation dependent.Cat Plus Plus
@CatPlusPlus not again... Everything question that asks about vtable is by definition implementation dependent. No need to point in restating the obvious.David Rodríguez - dribeas
Technically, it must set the pointer before the constructor is executed, because the object is an object of the type at this time already (though not initialized). But then again, a vtable is not required by the standard at all, this only happens to be the common way virtual functions are implemented. Further, since the type is statically known within the constructor, virtual function calls that one might make from the constructor are statically resolved. Therefore it would actually be possible to initialize the vtable afterwards (without you noticing, even if it's wrong).Damon
@Damon: Not really, you are allowed to pass *this to a function that takes a reference to your base type, and call from there the virtual function. The dispatch inside that other function must be dynamic, as the compiler does not know who the caller is.David Rodríguez - dribeas
@Als: I guess it depends on whether you want a theoretical approach to computer science or a practical one. I don't know of any alternative other than vtable and vptr's ever been implemented for C++, and the behavior mandated in the standard determines how the vptr has to be updated (if that is the solution of choice for dynamic dispatch). Yes, it is not mandated by the standard, but at the same time is virtually implementation independent in the sense that all implementations are the same to this respectDavid Rodríguez - dribeas

5 Answers

10
votes

This is strictly Implementation dependent.

For Most compilers,

The compiler initializes this->__vptr within each constructor's Member Initializer list.

The idea is to cause each object's v-pointer to point at its class's v-table, and the compiler generates the hidden code for this and adds it to the constructor code. Something like:

Base::Base(...arbitrary params...)
   : __vptr(&Base::__vtable[0])  ← supplied by the compiler, hidden from the programmer
 {

 }

This C++ FAQ explains a gist of what exactly happens.

9
votes

The pointer to the vtable is updated on entry to each constructor in the hierarchy and then again on entry of each destructor. The vptr will start pointing to the base class, and then will be updated as the different levels are initialized.

While you will read from many different people that this is implementation defined, as it is the whole choice of vtables, but the fact is that all compilers use vtables, and once you choose a vtable approach, the standard does mandate that the type of the runtime object is that of the constructor/destructor being executed, and that in turn means that whatever the dynamic dispatch mechanism is, it has to be adjusted as the construction/destruction chain is traversed.

Consider the following code snippet:

#include <iostream>

struct base;
void callback( base const & b );
struct base {
   base() { callback( *this ); }
   ~base() { callback( *this ); }
   virtual void f() const { std::cout << "base" << std::endl; }
};
struct derived : base {
   derived() { callback( *this ); }
   ~derived() { callback( *this ); }
   virtual void f() const { std::cout << "derived" << std::endl; }
};
void callback( base const & b ) {
   b.f();
}
int main() {
   derived d;
}

The standard mandates that the output of that program is base, derived, derived, base, but the call in callback is the same from all the four calls to the function. The only way that it can be implemented is by updating the vptr in the object as construction / destruction progresses.

1
votes

This msdn article explains it in great detali

There it says :

"And the final answer is... as you'd expect. It happens in the constructor."

If I might add, right at the beginning of the constructor, before any other code you might have in your constructor gets executed.


But be careful, let's say you have the class A, and a class A1 derived from A.

  • If you create a new A object, the vptr will be set right at the beginning of the constructor of the A class
  • But if you create a new object A1:

"Here's the entire sequence of events when you construct an instance of class A1:

  1. A1::A1 calls A::A
  2. A::A sets vtable to A's vtable
  3. A::A executes and returns
  4. A1::A1 sets vtable to A1's vtable
  5. A1::A1 executes and returns "
0
votes

In the body of the constructor, the virtual functions may be called, so, if the implementation used a vptr, that vptr is already set.

Note that the virtual functions called in a ctor are the ones defined in that constructor's class and not the ones possibly overridden by a more derived class.

#include <iostream>

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

struct B : public A
{
    virtual void foo () { std::cout << "B::foo" << std::endl; }
};


int
main ()
{
    B b;      // prints "A::foo"
    b.foo (); // prints "B::foo"
    return 0;
}
0
votes

While it's implementation dependent, it would actually have to happen before the body of the constructor itself is evaluted since you are allowed, per the C++ spec (12.7/3), to access non-static class methods via the this pointer in the constructor body ... therefore the vtable would have to be setup before the body of the construtor is called, otherwise calling virtual class methods via the this pointer would not work correctly. Even though the this pointer and the vtable are two different things, the fact that the C++ standard allows the this pointer to be used in the body of a constructor demonstrates how the compiler must implement the vtable for standards-compliant uses of the this pointer to work correctly, at least from a timing perspective. If the vtable were initialized during or after the constructor body is called, then using the this pointer to call virtual functions inside the body of the constructor or pass the this pointer to functions that depend on dynamic dispatch would be problematic and create undefined behavior.