views:

194

answers:

4

Possible Duplicate:
Overriding vs Virtual

In C++, whether you choose to use virtual or not, you can still override the base class function. The following compiles just fine...

class Enemy 
{
public:
    void SelectAnimation();
    void RunAI();
    void Interact()
    {
        cout<<"Hi I am a regular Enemy";
    }

private:
    int m_iHitPoints;
};

class Boss : public Enemy
{
public:
    void Interact()
    {
        cout<<"Hi I am a evil Boss";
    }
};

So my question is what is the difference in using or not using the virtual function. And what is the disadvantage.

+5  A: 

If Enemy::Interact() is not declared virtual, then calling Enemy::Interact() from a member function in the base class or via a pointer or reference to the base class will not call the derived class Interact() function.

For example:

Boss boss;
Enemy* bossEnemy = &boss;

boss.Interact();       // calls Boss::Interact()
bossEnemy->Interact(); // calls Enemy::Interact()

If you declare Enemy::Interact() as virtual, then Boss::Interact() will be called as you expect it to be.

The disadvantage of using virtual functions is that they are potentially more expensive to call than non-virtual functions. The disadvantage of not using virtual functions is that you probably don't get the results you want.

James McNellis
Virtual functions are always more expensive to call than non-virtual functions as the compiler cannot inline and optimize them. The exception is when the type is known statically, for example if the var is stack-allocated and accessed directly.
DeadMG
+17  A: 

If you have the code:

Enemy * p = new Boss;
p->Interact();

and Interact is not virtual, you will get Enemy's Interact. In other words, the function will be selected based on the apparent rather than its real type of the thing it is being called on. This is almost never what you want, so if you intend to call methods via a base pointer (for example, if you have a collection of base pointers in a vector or list) then the function should be made virtual in the base class. You will also need to make the destructor of such base classes virtual, so that the behaviour when deleting instances via a base pointer is well-defined.

anon
That makes alot sense. So if you use a program that relies heavily on casting classes to a base class, it will not work.
numerical25
@numerical25: That is called _polymorphism_. If you need polymorphic behavior, you want `virtual`.
sbi
So, why not use `virtual` for every function?
Omnifarious
@Omnifarious: `virtual` has a small indirection penalty both in terms of memory and function call overhead. In most implementations, it boils down to an extra pointer dereference into a small call table. In some situations, that overhead might be undesirable or prohibitive, so there's no reason to have to pay that overhead penalty if you don't need it.
greyfade
@greyfade: I know. :-) But the original poster asked two questions and this answer only answers one of them and answers it in a way that makes it seem like you'd __always__ want to use `virtual`.
Omnifarious
@greyfade Actually the indirection penalty is not that small. Yes you get one (or two indirections), but you also loose a bunch of optimizations that could be done with a non-virtual function (inlining, constant expressions, folding/unfolding, ...).
Let_Me_Be
@Let_Me_Be: That would be among "some situations [where it] might be undesirable or prohibitive."
greyfade
@greyfade But that's extremely hard to decide. You must be some sort of coding superhuman to detect this kind of performance problems upfront. "Don't use when don't need" is much safer approach.
Let_Me_Be
@Let_Me_Be: Isn't that what I said?
greyfade
+2  A: 

You tagged the question with game-development, and in such a scenario it might be hasty to disregard the extra call overhead for virtual calls: Elan Ruskin measured 50% increase in call overhead. The same guy (and many other game devs) consider it a good practice to use the added flexibility of virtual functions only when you have a concrete reason, and not just for the fun of it.

Here's a technical writeup of the reasons for the extra cost, and some musing on an extra-extra cost of pure virtual functions.

Ofek Shilon
+1 for being well-balanced. BTW The point of Elan Ruskin's ( aka Crashworks) post is that the vptr look up is not the issue - it's the instruction scheduling that's getting in the way
zebrabox
Very true. In fact Maciej Sinilo did try to isolate the vptr lookup cost, and found that it's non-measurable: http://msinilo.pl/blog/?p=401
Ofek Shilon
A: 

Polymorphism. Polymorphism. Polymorphism. :)

The virtual functionality is what makes C++ object-oriented. It's one of the major reasons why you are using C++ in the first place. Never think twice about using virtual if your design calls for it. Do not redesign your model simply to avoid virtuals.

Would you think twice about accessing a structure field even though there is an added cost to jump to the memory offset from the structure's base? No, of course you wouldn't if the design calls for it. Would you think twice about passing callbacks, event listeners, functors, or any other "logical" address that requires a jump to reach the actual data? Of course you wouldn't if the design calls for it.

On the flip side, there's no point to making a class member virtual if the design does not call for it, just as there's no need to pass around functors or create structs unnecessarily if the design doesn't call for it. The decision whether to use virtual is part of good OO design and implementation.

Performance

With respect to the so-called performance cost: First, this is a very old concern. The performance of the early C++ implementations of virtual calls could actually be measured without incredibly contrived code. As others have mentioned, today's technology largely obsoletes this debate.

Second, vector multiplication and similarly contrived examples are misleading. They appear to be measuring the difference between virtual calls and non-virtual calls. But they are not. They are measuring the difference between billions of virtual calls and billions of non-virtual calls to functions that do next to nothing. Is there real-world code that may be susceptible to this problem? It's certainly possible. When you find it, will the solution be to scapegoat the use of virtual in general? Clearly not. The solution is to optimize your exceptionally performance-sensitive code. As part of this hypothetical optimization, the removal of virtuals would be wise, but won't buy you much. If you've got code that performance sensitive, you'll need to optimize a heck of a lot more than discarding the virtuals.

Third, it's easily measurable, which is great, because you don't need to take our word for it. You can easily benchmark the difference with your compiler, on your target architecture, to assure yourself that there really is no performance difference.

John
fwiw, on a run-of-the-mill mac mini, the overhead of a virtual is 0.6 nanoseconds in the silly vector multiplication code.
John