views:

154

answers:

4

I was curious about C++ and virtual inheritance - in particular, the way that vtable conflicts are resolved between bass and child classes. I won't pretend to understand the specifics on how they work, but what I've gleamed so far is that their is a small delay caused by using virtual functions due to that resolution. My question then is if the base class is blank - ie, its virtual functions are defined as:

virtual void doStuff() = 0;

Does this mean that the resolution is not necessary, because there's only one set of functions to pick from?

Forgive me if this is an stupid question - as I said, I don't understand how vtables work so I don't really know any better.

EDIT

So if I have an abstract class with two seperate child classes:

    A
   / \
  /   \
 B     C

There is no performance hit when calling functions from the child classes compared to say, just a single inheritance free class?

A: 

The 'double dispatch' hit only occurs when the method is virtual. If the derived method is not virtual, there is no performance hit.

John Weldon
But if the parent method is pure virtual as in the OP's example, the derived method is also virtual.
Mark B
Correct. Thanks.
John Weldon
+2  A: 

I don't know what "one set of functions" you are talking about. You have two derived classes - B and C - with each having its own set of virtual functions. So, you have at least two sets, even if all functions in A are pure.

The virtual dispatch occurs when the compiler does not know the dynamic type of the object it is working with. For example, if your have a pointer A *p, it can point to an object of type B or type C. If the compiler does not know what is the actual type of the object p is pointing to, it will have to use virtual dispatch in order to call virtual functions through p.

P.S. There's no "virtual inheritance" in your example. The term virtual inheritance in C++ has its own meaning. And you are not talking about virtual inheritance here.

AndreyT
When I said one set of functions, I meant the functions from a single class. Sorry about the virtual inheritance thing. If I could ask a further question, how expensive is the vtable dispatch?Would start to take a tole when you use it very repeatedly? I'm thinking of having multiple versions of most objects in my project, so the user can on demand reload the program with debug objects which do extra checking, logging and ect.
Tomas Cokis
+4  A: 

There is no hit for calling nonvirtual functions in the child class. If you're calling an overridden version of your pure virtual function as in your example, then the virtual penalty may still exist. In general it's difficult for compilers to optimize away the use of the virtual table except under very specific circumstances, where it knows the exact by-value type of the object in question (from context).

But seriously don't worry about the overhead. It's going to be so little that in practice you will almost certainly never encounter a situation where it's the part of code causing performance bottlenecks. Use virtual functions where they make sense for your design and don't worry about the (tiny) performance penalty.

Mark B
Thanks for the straight answer and overall advice on coding =)
Tomas Cokis
I've experimentally measured the overhead of a virtual function call as being about 7 nanoseconds higher than a direct function call (on a 3GHz processor). Whether that adds up to something significant or not depends on just what you're doing.
Crashworks
+3  A: 

Let's say you have a hierarchy like this...

class Base
{
public:
    virtual int foo() = 0;
};

class Derived1
{
public:
    int foo() { return 1; }
};

class Derived2
{
public:
    int foo() { return 2; }
};

and we have a function like this...

int get_foo(Base* ptr)
{
    return ptr->foo();
}

Assuming there is no inlining where the compiler has more information than that which is presented here, the compiler will generate get_foo to be the following (x86):

push ecx                             ; Save ecx.
mov eax, [esp + 8]                   ; Move ptr into eax.
mov ecx, eax                         ; Set up the __thiscall.
call [eax + {vtable offset of foo}]  ; Call foo.
pop ecx                              ; Reset ecx.
retn                                 ; Return foo's return value.

Now, given that we're calling the vtable offset, this means double-dispatch will be used. At the offset ptr + {vtable offset of foo}, there is a pointer to the implementation of foo() for whatever class was passed into get_foo. This pointer is then dereferenced, and the target is called.

Now, we instead accept the concrete class Derived1 as opposed to base:

int get_foo(Derived1* ptr)
{
    return ptr->foo();
}

Since foo's location is known at compile-time (due to it not being declared virtual) [ed- might be wrong. comments shall decide], the compiler is free to optimize that function to...

push ecx                            ; Save ecx.
mov ecx, [esp + 8]                  ; Move in the "this" pointer for __thiscall
call {location of Derived1::foo()}  ; Call derived's foo() function.
pop ecx                             ; Restore ecx.
retn                                ; Return foo's return value.

Which is one less instruction, and one less dereference!

Moral of the story, don't worry about it. The difference a v-table lookup in your code is negligible, taking very few clock cycles. And above all else, remember to profile before optimizing.

NOTE: If I'm wrong about anything (and I probably am, due to the length of this), let me know in the comments :)

Clark Gaebel