Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I am considering using a class hierarchy with more than a single level of inheritance, where virtual member functions form a "chain", for example:

struct Base
{ virtual void foo(); };

struct D1 : Base
{ virtual void foo(); };

struct D2 : D1
{ void foo(); };

However I would like to know before using similar code in practice if this would cause additional dynamic dispatch overhead when calling trough a base class pointer. Consider the following example:

D2 instance;
D1* d1ptr = &instance;
Base* baseptr = &instance;

//normal function call to "D2::foo()", no dynamic dispatch.
instance.foo();
//virtual function call to "D2::foo()", one dynamic dispatch.
d1ptr.foo(); 
//virtual function call to "D2::foo()", does this incur additional
//..overhead compared to "d1ptr.foo()"?
baseptr.foo();
share|improve this question

1 Answer 1

up vote 6 down vote accepted

In your example, the depth of the inheritance tree does not affect performance. The reason is simple, every instance has its pointer to some vtable (containing function pointers), and a virtual function call goes just thru that vtable.

In other words, your code works like the following C code:

struct vtable {
   void (*fooptr) (struct D1*);
};

struct D1 {
   const struct vtable*vptr;
};

struct D2 {
   const struct vtable*vptr;
};

And e.g. baseptr->foo() is "transformed" at compilation time to baseptr->vptr.fooptr(baseptr) (and of course d1ptr->foo() is "transformed" to d1ptr->vptr.fooptr(d1ptr) etc...)

So the execution cost is the same: get the vtable, and call indirectly the function pointer inside. The cost remains the same even if you had a struct D4 subclass of struct D3 subclass of struct D2 subclass of struct D1. You could have a struct D99 with 99 inheritances and the execution cost would remain the same.

On some processors, any indirect call may be slower than a direct call, e.g. because of branch predictor cost.

The data of the vtable themselves is built at compilation time (as constant static data).

Things become a bit more complex with virtual inheritance and/or multiple inheritance

BTW, some C object frameworks (e.g. GObject from Gtk, or several data structures inside the Linux kernel) also provide their vtable (or class data). Pointing to a data structure containing function pointers is quite common (even in C). Read also about closures and you'll see a relation with "vtables" (both closures and objects are mixing code with data).

Some C++ compilers (e.g. GCC) may provide devirtualization as an optimization technique.

share|improve this answer
    
C++ 11 provides keyword final, does it not, which would make devirtualization of leaf functions straightforward. I have seen gcc devirtualize without final, playing around on the godbolt page, but it's almost hilariously fragile and cannot be relied on. –  Nir Friedman 11 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.