Advertisement

Virtual functions? Inheritance? Why use them???

Started by July 26, 2001 02:46 PM
26 comments, last by Ghostface 23 years, 6 months ago
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.
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!"
"You call him Dr. Grip, doll!"
Advertisement
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?
------------------------------"I do not feel obliged to believe that the same God who has endowed us with sense, reason, and intellect has intended us to forgo their use. " - Galileo Galilei
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...).

I know only that which I know, but I do not know what I know.
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.
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
------------------------------"I do not feel obliged to believe that the same God who has endowed us with sense, reason, and intellect has intended us to forgo their use. " - Galileo Galilei
Advertisement
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
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.

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
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.

This topic is closed to new replies.

Advertisement