views:

334

answers:

5
+5  A: 

The calls on b are static - the compiler knows for sure at compilation time what the type of b will be at runtime (obviously a Bar) so it will directly use the addresses of the methods that will be invoked.

Virtual only matters when you make a call via pointer/reference as the call could have different targets at runtime. This would matter if, for example, you called function1 on a pointer and during runtime changed the actual type that the pointer pointed to.

Now the situation here, where you call function2 on f is tricky for two reasons: the function is never overridden, and you use a reference which cannot be reassigned. Therefore, a really smart compiler that sees all input files could conceivably figure out what the target of the call really will be with 100% confidence (since you're not going to add new classes to the already compiled code). However, AFAIK, the compilers does not have to do it so you would pay the cost.

Generally speaking, if you don't plan to override a function ever, don't make it virtual.

Uri
`function2()` is declared `virtual`, so it will be in the vtable. Therefore, `f.function2();` will call the function via the vtable. The fact that neither `Foo` nor `Bar` override `function2` does not prevent a `Foo` subclass declared outside this compilation unit from overriding it, and a `Foo` can't optimize out the vtable dereference.
Mike D.
@Mike D: Hence "a compiler that sees all input files". I'm not aware of any such compilers because typical C++ compilers go for separate compilation, but I suppose somebody could write something like that.
Uri
@Uri: Visual C++ with /LTCG (link-time code generation) sees all input files...
Roger Lipscombe
@Roger: Nice.... When did they add that? Admittedly, I haven't compiled C++ since VC6...
Uri
Matthieu M.
I remember a developer that had his own LTCG: He'd have one .cpp file and everything else was in .h files. Every build was a full build. He claimed it avoided several problems (mostly with template instantiation; this was back at gcc 2.7), dependency problems, incomplete builds, complex makefiles, etc. It also made it impossible for the rest of us to use his code as libraries. So when he left, we barely noticed.
Mike D.
A: 

Here's something you can try. Wrap those three function calls in a for-loop with a million iterations. Then run the program through a profiler to get a feel for what the cost differences are. If you run linux, callgrind (profiler) and kcachegrind (visualize the results) will give you excellent insight into this, even down to the assembler code level.

Kristo
That's not a very suitable benchmark. In reality virtual function calls often confuse branch prediction and lead to pipeline bubbles. But when just calling the same function again and again in a loop it will predict it correctly every time.My advise would be to avoid virtual function calls in time critical code, but only if you otherwise would not end up using switch statements everywhere to simulate them.
Axel Gneiting
+3  A: 

Elan Ruskin did a benchmark on this topic:

http://assemblyrequired.crashworks.org/2009/01/19/how-slow-are-virtual-functions-really/

Of course it is on you to decide how practice-oriented his results are for you :-)

vobject
A: 
In C++, To achieve run-time polymorphism 2 things are required:
1.Functin must be a member of the class and declared as virtual.
2.Use Pointers or references to make dynamic funtion dispatch possible.

e.g.
   Derived d;
   Base &refBase = d;
   Base *pBase = d;

   d.foo();
   // resolved at compile time based on the static type of object (Derived)

   refBase.foo();  //will resolve at runtime
/* Here refBase is reference to Base class , but its dynamic type reference to 
Derived class object so its refering to derived class object and accordingly derived  class funtion is called (using look up in vtbl) and similarly for pointers.
*/

 So in your case first 2 funtion calls are resolved at compiler time since invoked by
 object rather than pointers or references .

 The last call will be resolved at run-time by making  lookup in vtable of derived class. 
Ashish
A: 

The actual call to a method takes about twice as long for a virtual method. The thing to keep in mind is that inlining takes none whatsoever. If you are ok with a call in the first place, you are usually ok with a virtual call as well, and when you're not you can often inline it away. Especially keep in mind call time doesn't factor in the actual code that then gets run.

Charles Eli Cheese