9

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?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Abhineet Mishra
  • 113
  • 1
  • 6
  • 1
    It's entirely implementation dependent. – Cat Plus Plus Oct 28 '11 at 20:29
  • 7
    @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 Oct 28 '11 at 20:34
  • 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 Oct 28 '11 at 20:36
  • @DavidRodríguez-dribeas: I agree this Q deserves to be answered,and it is indeed a valid Q,but no harm in stating that this is implementation defined because lot of new users(trust me I was one too)are really not aware that the entire virtual Mechanism is Implementation dependent,more so for those who turn to programming from an non computer science background. – Alok Save Oct 28 '11 at 20:48
  • 3
    @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 Oct 28 '11 at 20:54
  • 1
    @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 respect – David Rodríguez - dribeas Oct 28 '11 at 20:58
  • @DavidRodríguez-dribeas: I agree,Never have seen a compiler implementing dynamic dispatch in any other way.Not so long ago,I was intrigued by the very same Q about alternate dynamic dispatch mechanisms and asked a Q here on SO,Not sure if you already read it before,but you might find the content interesting.here it is [A question about virtual mechanism in C++](http://stackoverflow.com/questions/4352032/a-question-about-virtual-mechanism-in-c)(I admit the Q title is really bad,those were my early days in SO) – Alok Save Oct 28 '11 at 21:05
  • @DavidRodríguez-dribeas:Ah,ignore the link, just saw comments from you on some answers in the said thread. – Alok Save Oct 28 '11 at 21:14
  • @Als :) I had read (and forgotten) the accepted answer... I am actually interested in knowing what the language can be and how *performant* it actually is. There is quite a few people that consider virtual dispatch through a vtable *inefficient* for tight loops, and the lookup of the vtable equivalent by memory address of the caller is surely going to be a few times as expensive as following the vptr to the vtable and dispatching from there... And I am not only thinking on actual processor instructions, but also locality of data (walking the Judy tree can trigger a couple of cache misses...) – David Rodríguez - dribeas Oct 28 '11 at 21:24

5 Answers5

10

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.

Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 2
    This is only as implementation dependent as the choice of using a vtable. For all compilers that use vtables (i.e. *all*) there is no choice but to update the vptr at each level of construction/destruction. – David Rodríguez - dribeas Oct 28 '11 at 20:47
  • @DavidRodríguez-dribeas: I agree,All compilers I know of use the `vtable`,`vptr` mechanism,and should use such an mechanism but since implementations are not bound to do so by the Standard,hence the first statement. – Alok Save Oct 28 '11 at 20:51
  • @DavidRodríguez-dribeas I don't blame him for adding the disclaimer - too many people will bypass your answer or even downvote if you don't do it. – Mark Ransom Oct 28 '11 at 21:09
  • I would also add, that it is worth to note that, while the virtual pointer is set, as mentioed in the above answer, when the constructor of the object is executed, the virtual **table** itself, was created by the compiler during compilation phase. – Guy Avraham Feb 20 '23 at 15:55
9

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.

Pubby
  • 51,882
  • 13
  • 139
  • 180
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
1

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

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.

Jason
  • 31,834
  • 7
  • 59
  • 78
  • Yes, but that is only true for `this`. See my comment above. The class that virtual functions belong to is known during the constructor, there is no vtable needed to resolve them. – Damon Oct 28 '11 at 20:41
  • vtable and `this` are two entirely different things. – Pubby Oct 28 '11 at 20:45
  • 1
    @Pubby8 ... completely agree but just saying that 1) in the constructor body you're allowed to access non-static class methods, and 2) if you do that via the `this` pointer, and the vtable is not setup, then you're going to run into some problems calling non-static virtual functions as virtual function calls happen through the vtable for the class instance the `this` pointer is pointing to. – Jason Oct 28 '11 at 20:52
  • @Damon **Your comment above is wrong.** You consider a special case (a degenerate case), make a correct statement about it, then generalise it. You are correct about these facts: (1) inside the constructor's body, the dynamic type of `*this` is known by definition (2) a virtual call to an object whose dynamic type is known by the compiler need not use the vptr. And that's all. You seem to believe that there is a special rule about `this` in the constructor body, but there is not. – curiousguy Sep 13 '15 at 23:24
  • **You mix special cases, which can be optimised, and the general case**. In special cases, the compiler can avoid setting the vptr at the beginning of the constructor, because it will be set later by constructor of a derived class. F.ex. when the constructor doesn't use `this` explicitly or implicitly as an argument of functions; or when the functions are inlined, etc. **In general, a constructor may use `this` in any way it likes.** It is a normal pointer, which may be copied around and used for virtual calls that cannot be "devirtualized" in general (see halting problem). – curiousguy Sep 13 '15 at 23:28
  • @curiousguy: Any virtual function called from a ctor is called either via a fully qualified name (in the case of multiple inheritance and functions with identical names in several base classes) or it is 100% certain which base class it belongs to (name either is unique, or there is only one base class), or the build breaks (call is ambiguous). There is technically not even a need for a this-pointer, since the object's static (_not_ dynamic!) type is by definition exactly known, and it is exactly known which function must be called. That is not a special case, but the only possible case. – Damon Sep 14 '15 at 09:50
  • @Damon You have no idea what you are talking about. Qualified calls are not relevant here. Unqualified calls to virtual function use the dynamic type, period. – curiousguy Sep 14 '15 at 21:42
  • @curiousguy: Why is it that the most clueless people are aways the most aggressive... I shouldn't waste time discussing this. Calling a virtual function from a constructor means calling an exactly known function from an exactly known type. Either because there is only one possible candidate (single inheritance), or because you must fully qualify it (when there are several ambiguous names in muliple inheritance). This is not dynamic dispatch, but static. But of course, as someone who knows what he is talking about, you know that. :-) – Damon Sep 14 '15 at 21:53
  • @Damon I have worked in the ISO C++ committee. Have you? – curiousguy Sep 15 '15 at 01:16
  • @curiousguy: Oh wow, worked for the ISO committee, did you. I'm impressed. I'll end this discussion with linking to a couple of questions that you have asked on this site: http://stackoverflow.com/questions/32045888/are-pointer-variables-just-integers-with-some-operators-or-are-they-mystical http://stackoverflow.com/questions/32100245/dereferencing-a-50-out-of-bound-pointer-array-of-array http://stackoverflow.com/questions/32048698/is-memcpy-of-a-pointer-the-same-as-assignment – Damon Sep 15 '15 at 08:50
  • @Damon Can you help me on any of these questions? – curiousguy Sep 23 '15 at 07:27
  • @curiousguy: You can answer them all yourself according to paragraph 3.7.4.3 (which from what you claimed earlier, you should be familiar with). – Damon Sep 23 '15 at 09:30
  • @Damon If you think "Safely-derived pointers" is the answer to some of my questions, please post an answer. – curiousguy Sep 23 '15 at 20:12
0

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;
}
chill
  • 16,470
  • 2
  • 40
  • 44
  • They are most definitely called in the constructors, according to ISO/IEC 14882:2011(E) [class.cdtor] 12.7 Construction and destruction [#4] "Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2)." – chill Oct 28 '11 at 20:48
  • 1
    @Pubby8: While in this particular case the constructor can use static dispatch, not in all cases it can be done. In particular the same outcome is mandated by the standard if the constructor calls a dispatcher function passing a reference to `A` and the dispatcher calls the virtual function, and in that case, the compiler cannot use static dispatch, as it does not know while processing the dispatcher where the call comes from. – David Rodríguez - dribeas Oct 28 '11 at 20:51