Archived

This topic is now archived and is closed to further replies.

Ghostface

Virtual functions? Inheritance? Why use them???

Recommended Posts

Compared to most of the people here, I am new to programming. The only language that I have any experience with is C++, which I have been learning for the past 9-10 months. But, something perplexes me: why would anyone want to use virtual functions? They seem kind of pointless to me. Why not just override the base class''s function? From all of the examples I''ve seen, it seems that in order to use a virtual function, you must have an instance of a base class that points to an instance of a derived class, but must decide which function to use at runtime. Or something like that. It''s all gibberish to me. So...someone help me out please.

Share this post


Link to post
Share on other sites
Well, you''re sort of on the right track here. If a class''s function is virtual, it can be overridden in a child class. This is very, very useful. Here''s a stupid little example...suppose you have a generic CEnemy class, with a virtual function attack(). Then, suppose you have two child classes, CTroll and COgre. Each of these also has an attack(). Now, the magic of virtual functions:
  
CEnemy* pEnemy = new CTroll(...);
pEnemy->attack(); // CTroll''s attack() function gets called
pEnemy = new COgre(...);
pEnemy->attack(); // COgre''s attack() function gets called

I hope you can see just how useful this can be. Another example would be if you are iterating through a list of enemies, and each enemy is of a different type. All you have to do is call each enemy''s attack() function, and you know that the correct one will be called.

~~~~~~~~~~
Martee

Share this post


Link to post
Share on other sites
A virtual function basically forces derived objects to also perform the function according to what the base class has for that virtual function prior to performing the derived class''s overriden function.

The most common example of this is a destructor. It is wise to make destructors virtual due to the fact that you might need to delete allocated memory in the base class. For instance:


class Base
{
public:
Base() { myItem = new ITEM; } // default constructor
virtual ~Base() { delete myItem; } // virtual destructor
ITEM *myItem;
}

class Derived : public Base
{
public:
Derived(); // default constructor
virtual ~Derived(); // virtual destructor
}


In the previous example, myItem was allocated as memory that will require specific deletion. If the destructor were not virtual, then any constructed instances of Derive would not "be aware" that the memory needed to be deleted. Due to the fact that the destructor is virtual, the destructor for Base will be called, and the memory properly released, before the destructor for Derive will be completed. This is why destructors are always declared as virtual.

Other examples of wanting to use this functionality would be anything you wish to repeat across all derived classes. For instance, if you always wanted to draw something on every derived view, you could make the OnDraw virtual to force the same thing to be drawn first for all views.

There are several gotchas regarding this involving calling member functions from within virtual functions and vice versa, but I think this is enough to digest for now *smile*

-fel

Share this post


Link to post
Share on other sites
I forgot to note that base class constructors are implicitly virtual due to the fact that the base class must be constructed in conjunction with (and previous to, for that matter) any derived classes, though constructors are not labelled as such... in case there''s any confusion as to how the Base constructor got called in the first place.

-fel

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Your game might have a lot of objects that need to be updated every tick. They might be of many different types but fundamentally they need to get updated every tick. So you want to store them all in a list or a vector and update them all by iterating through the list right? You can''t do that unless you use pointers to derived classes. So what you do is you make a base class Updatable and give it a virtual method Update(). Then derive all of the things you want to be able to update from this class and implement the method. Now you can loop through. Oh and you can''t override a non virtual function, the word virtual means overridable. It might seem like you can but you aren''t doing what you think you are.

Another common use is for implementing what is known as the "strategy pattern". Let''s say you have a monster type and you need to make AI for it. Every now and then it appraises the situation and decides what to do. You could have a case statement, and have code for each situation. That is probably the best solution if you only need simple AI. However if you want things to be more complex or flexible it is time to break out inheritance. Make a Reaction class with a HandleSituation() method. Have Reaction* variables for all the different situations and put subclasses in them. Now in the case statement instead of putting the code directly call the HandleSituation method of the appropriate Reacton variable. There are some nice benefits to doing this. For one you can change behavior at runtime. You might have a spell that makes monsters laugh in response to certain situations, now it is easy, just swap in a subclass that does just that. You can also use the same set of Reaction classes to do all the AI for all your monsters, it makes things easier.

There are more uses of inheritance too but they mostly revolve the basic concept of changing behavior while retaining the same interface.

Share this post


Link to post
Share on other sites
The main contribution is interface reuse, which means that you build on a foundation of ABSTRACT base classes. Without virtual functions and the accompanying vtbls you couldn''t do this.

This is what COM is all about.

Share this post


Link to post
Share on other sites
I would like to thank everyone for their attempts to help me to understand the use of virtual functions, but I''m afraid that I still don''t understand. Could someone please give me a practical example of something that you would NOT want to do/cannot do without virtual functions?

They still seem pointless to me. But then again, I''m a novice programmer...

Share this post


Link to post
Share on other sites
I happen to have two C++ books (Teach Yourself C++ in 21 Days and Practical C++). And neither one of them does a very good of explaining the practicality/uses of virtual functions.

And I''m only 15, which is not quite old enough to get a job at most places

Share this post


Link to post
Share on other sites
Well, you won''t find any examples of where inheritence/virtual functions are necessary... Because they aren''t. C++ is Turing-complete without virtual functions. What they do is make certain jobs easier.

Take a look at this thread:
http://www.gamedev.net/community/forums/topic.asp?topic_id=55540

Look at the description of the problem, then at the two different solutions proposed. One of those solutions involves using virtual functions and inheritence. The other involves using the C equivalent, function pointers.

Share this post


Link to post
Share on other sites
Any O''Reilly books are generally pretty good, and there is an Osbourne book called something like "Complete C++" or something that i''ve found useful.

Think about pointers too... when you first learned them, i''m sure you were like, "What the heck is a pointer good for?". Then, in time, you realize how invaluable they are (speed, by ref vs. by val, etc.).

"You call him Dr. Grip, doll!"

Share this post


Link to post
Share on other sites
As always, I would first like to thank everyone for their posts and attempts to remedy my ignorance.

the_grip: I laughed out loud when I read your post. Not that anything you said was particularly funny/stupid, but it''s just that, in what little programming experience I have, I have YET to find a use for pointers/references. They still seem kinda stupid to me. Heck, I can''t even remember when to use that little dereferincing asterik or not. It''s all very confusing to me. But, remember, I''ve only been programming for about 9 months, and I''ve only been doing console apps. And C++ is the ONLY language that I have any significant experience using (I once made a "choose your own adventure" style text game using qbasic a few years back, but I don''t really count that...). Something tells me that my ignorance on the uses of pointers is gonna come and slap me upside the head REALLY soon, because I''m starting to learn the Win32 SDK. But, that''s subject matter for an entirely different thread

In any case, all comments and suggestions are appreciated. However keep in mind that I have only been programming for about 9 months, and I''m not quite up to understanding all the intricacies of interfaces and COM and the like. All I want is help understanding the basic practical uses of virtual functions. However, if all you can give is examples having to deal with interfaces, I suppose I don''t have a choice, do I?

Share this post


Link to post
Share on other sites
Let me take a stab at it in a more indirect manner. Let''s say you want to have 3 races in your game. Elf, Human, and Ogre for example. The elf, human, and ogre have quite a few things in common. 2 arms, 2 legs, 2 eyes, and a mouth. Also, all 3 are entities. So the race classes inherit these characteristics from the base class, Entity.

  
class ENTITY
{
virtual void Walk() {/* universal walk code */;}
virtual void Pickup() {/* universal pickup code */;}
virtual void Talk() {/* universal talk code */
;}
};

class ELF : public ENTITY
{
int myWeight;
int myStrength;
int myAge;
};


This allows you to only have to code walking code for all three races once. However, say you add a 4th. A dragon, then you would add a walk function to the dragon class to override the universal function and perform the 4 legged walking code.

  
class DRAGON : public ENTITY
{
virtual Walk() {/* Special dragon walk code */;}

int myWeight;
int myStrength;
int myAge;
};


Note that the dragon''s walk is also virtual. It shouldn''t make any difference if it''s virtual or not, but it would then allow you to create a class for per say, a gold dragon. A gold dragon would be a dragon with special properties.

  
class GOLD_DRAGON : public DRAGON
{
// special gold dragon qualities

};


Sure you could get by with custom making classes for everything, but using inheritance just makes things easier in the long run and insures that objects get the things they need. It''s also much easier to manage than custom classes all over the place.

You may not fully grasp the idea of inheritance, not even I do. I''m sure I have much to learn. But the above is the way I picture it. I hope this helps. Another way to look at it would be, a family tree or the scientific classification chart (kingdom, class, phylum etc...).

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
pointers create relationships. You might not need them yet but eventually you will need to create a relationship other than "has" and you will understand. If you ever find yourself writing the same case statement more than once or that you are using function pointers you''ll probably want to think about using inheritance. Until then it is ok that you don''t know how to use them, just keep programming the way you are. Eventually though you will want to do something more advanced and these features will come in handy.

Share this post


Link to post
Share on other sites
Daishi, thanks for the example, but there's still a resounding question in my mind: why not just override the base class's function? Thus far, it seems that the only use for a virtual function is to serve as a sort of "template" for functions in derived classes. (and I mean that strictly in the colloquial sense of the word). It seems as though that's the only reason for abstract base classes as well. Correct me if I'm wrong.

Edited by - Ghostface on July 30, 2001 10:51:34 AM

Share this post


Link to post
Share on other sites
OK here''s my take on them (v funcs)& why you just can''t override them, everyone has given examples - but not really explained why you need to call them virtual rather than just overriding them. It is to do with typing. Say you have a class Base & a derived class Derived. You also have an array of pointers to the class Base. Base * bpointers[10];
So C++ knows if has an array of pointers to classes of type Base. As you know you can assign a Base class pointer to point to a child (in this case Derived), so that
bpointers[0] = new Derived() is valid. If you''re not following this - we''ve got problems.
Now lets say that you have a function called CallMe, which prints out "B" for Base classes & "D" for Derived classes. If you DON''T make it virtual and run through the array calling bpointer->CallMe(); you will always get "A" printed out, even if the whole array is Derived classes. The reason is an optimisation. Because C++ compiler KNOWS that the whole array are bpointers & it KNOWS that your function is NOT virtual, it will ALWAYS call the Base::CallMe function, it has no need to look anywhere else. So to make it examine which function should be called (at run time) you have to make it virtual, then it won''t just look at the static declaration in code to find the kind of object it is pointing at, it will actually ask - am I a Base or a Derived? And then run whichever function.
Also I would say "understand pointers & references VERY well". If you don''t know what they''re for, here''s one example. It reduces stack space when you pass parameters (only a 32bit pointer has to be passed, rather than a huge object), and it prevents nasty copy constructors being called. For speed you want to avoid copy constructors & tempory objects & the = operator like the plague. You also don''t want to make you arithmetic operators return tempory objects, ''cos it slows things down. If you don''t under stand, mail me at
brad_(take this out - I hate spam)beveridge@hotmail.com

Cheers
Brad

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by Ghostface
Thus far, it seems that the only use for a virtual function is to serve as a sort of "template" for functions is derived classes. (and I mean that strictly in the colloquial sense of the word). It seems as though that''s the only reason for abstract base classes as well. Correct me if I''m wrong.


Exactly! That is right, the whole point is to have the same interface but a different implementation. Now you can swap in and out objects of derived classes without changing any other code. Now maybe you haven''t come across the need to use it, that''s quite understandable or maybe you are using a more complicated way to do the same thing. However I think you ought to explain what you mean when you say "why not just override the base class''s function?" because you cannot do that in C++ without using virtual functions. You might think you can but you can''t. By definition overriding means using virtual functions. Overloading means making a second version with different arguments, and hiding (almost certainly what you are doing) means that the two functions have nothing more in common than their names, they are not actually connected logically according to the computer.

Share this post


Link to post
Share on other sites
To Anon above. I think you kinda can override without the virtual key word, but it''s messy. Say we have class Base & Derived, both with ::CallMe(), Base prints out "B", Derived prints out "D"
if we go Base *b = new Base();
b->CallMe() we will get "B"

Base *b = new Derived();
b->CallMe() we get "B"

Derived *d = new Derived();
d->CallMe() we get "D"

Now if we go
Base *b = new Derived();

(static_cast(b))->CallMe() we will get "D" (I think)
perhaps it should be dynmic_cast (actually I''m almost sure it should).

This is all pretty acedemic - just use virtual & get over it. Also if I''ve made any glaring mistakes, please correct me ''cos it''s always good to learn

Brad

Share this post


Link to post
Share on other sites
You can override without the virtual keyword, but there is a big difference in what version of the function gets called. If we have this:
  
class Base
{
public:
void DoStuff();
};

class Derived : public Base
{
public:
void DoStuff();
};

Base *pBase1 = new Base;
Base *pBase2 = new Derived;

pBase1->DoStuff();
pBase2->DoStuff();

As a result of the function not being declared virtual, the function to call is chosen based on the pointer type itself. In this case, they''re both Base type, so both function calls will call the base version of the funciton, even though we overrode it in Derived. If the function was declared virtual, the function would be chosen based on the type is points to, which would mean the Base version gets executed in the first call and the Derived version get executed in the second call.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I''ve always heard that called "hiding". In those examples the only thing that is the same is the function signature. The compiler doesn''t see the connection that we make in our minds, other than it has to hide one, just like it would hide a variable with the same name if a new one is introduced in a scope.

Share this post


Link to post
Share on other sites
Ghostface, if you are still unsure what the benifits to virtual functions are, then hopefully the thread below will clear things up.

http://www.gamedev.net/community/forums/topic.asp?topic_id=23993

Also, try searching the forums on questions like these, as they''ve been asked and answered many times before.

Hope this helps!


- Houdini

Share this post


Link to post
Share on other sites
Virtual functions allow the correct version of a function to be called based on the type that is pointed to as opposed to the type of the pointer variable itself. Virtual functions use late-biding to determine what to call, and regular functions use early-binding, when the program is compiled. since we as programmers only have control before the code is compiled, having programing features that allow the program to make dynamic decisions about what functions to call is very advantegeous.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
yeah, i was basically going to say what zipster said. all you have to do is declare one pointer, for the base class, and just have it reference the derived classes so that it can call those functions for the derived class, instead of have to create pointers for each and every class.

if you tried to override functions and tried to call functions for the derived class, using a base class pointer, it wouldn''t work, it would call the base calss funcion.

Share this post


Link to post
Share on other sites