Jump to content
  • Advertisement

Archived

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

Virtual Functions

This topic is 6474 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Can someone please explain why virtual functions is so great in OOP programming? I guess I just don't fully understand what a virtual function is and why and when it would be used. I am mostely a C programming and trying to learn C++ and COM programming. The two areas i'm having trouble with is the concept behind Virtual functions and what astraction does for OOP and the benefits you receive by using them. Another thing, I notice on a virtual function you have a "= 0" at the end. What is this for...example virtual void DoSomething() = 0; If anyone can help me better understand these concepts I would be very thankful. Thank you in advance for your help. Braves Edited by - braves on 8/29/00 11:13:58 AM

Share this post


Link to post
Share on other sites
Advertisement
ok. first of all virtual functions with "=0;" appended to it, set the function to be pure virtual setting the class as abstract. an abstract class cannot be instanciated (created), but only derived from. and the derived class must override the pure virtual functions.

virtual functions allow a standard mechanism for calling methods which act upon a class, which allow you the user to use the class in ambiguity.

class Base {
func1(void) { printf("base: func1"); }
virtual func2(void) { printf("base: func2"); }
};

class Derived : public Base {
func1(void) { printf("derived: func1"); }
func2(void) { printf("derived: func2"); }
};

Derived d;
Base *b;

b = (Base *)Derived;
b.func1() : output = base: func1
b.func2() : output = derived: func2
d.func1() : output = derived: func1
d.func2() : output = derived: func2

hope this helps.

Share this post


Link to post
Share on other sites
quote:
Original post by braves

I guess I just don''t fully understand what a virtual function is and why and when it would be used... Another thing, I notice on a virtual function you have a "= 0" at the end.




The chief value of virtual functions is the ability to ''hide'' the implementation of a function at the point the function call is made. For example, if I write some code which uses the virtual function int getItemCount() do I really need to know how the items are stored? There may be an array of items, a linked list of items, a tree of items, whatever. I just call getItemCount() and it tells me how many items there are.

Because I have used a virtual function, I can change the way the items are stored whenever I want. I just write a new function to count the list items, then point getItemCount() at this new function - no other code needs to be changed, no matter how many times I have used getItemCount() .

Within the context of game programming, I might have a virtual function void ProcessUserInput which can point to different functions depending on whether the user has a keyboard, joystick, mouse, etc. I can then allow the user to switch the input type at any time, without worrying about this in the code.

Oh, your other question... a virtual function is like a ''pointer to a function'', so setting it to 0 (or NULL) ensures that it does not take on some spurious value (which would cause major problems at run-time).

Share this post


Link to post
Share on other sites
ok. first of all virtual functions with "=0;" appended to it, set the function to be pure virtual setting the class as abstract. an abstract class cannot be instanciated (created), but only derived from. and the derived class must override the pure virtual functions.

virtual functions allow a standard mechanism for calling methods which act upon a class, which allow you the user to use the class in ambiguity.

class Base {
func1(void) { printf("base: func1"); }
virtual func2(void) { printf("base: func2"); }
};

class Derived : public Base {
func1(void) { printf("derived: func1"); }
func2(void) { printf("derived: func2"); }
};

Derived d;
Base *b;

b = (Base *)Derived;
b.func1() : output = base: func1
b.func2() : output = derived: func2
d.func1() : output = derived: func1
d.func2() : output = derived: func2

hope this helps.

Share this post


Link to post
Share on other sites
When something says

virtual void DoSomething()=0;

means you are declaring a pure virtual function. By doing this it also makes that class an abstract class so that you cannot make an instance of that class. You can make extend this class with a sub-class, but if you don''t overide the function, that sub-class will also be abstract.

As for the use of virtual functions, say you had several levels of derived classes. You could have a pointer to your base class that you could reassign to any of your derived objects, and the virtual functions would call their derived functions. If they weren''t virtual, they would all the base class function.

I hope that makes sense, but if anybody has a better answer, go nuts, i won''t get offended.

Share this post


Link to post
Share on other sites
I think I understand virtual functions now! Ok, tell me if i''m correct.


class Base
{
virtual func2(void) { printf("base: func2"); }
};

class Derived : public Base {
func2(void) { printf("derived: func2"); }
};

void main
{

Derived d;
Base *b;
b = (Base *)Derived;
b.func2() : output = derived: func2
b = Base;//Don''t have to cast it because it is a Base object.
d.func2() : output = base: func2
}

now...what if I put another function in it that''s not virutal like...say DoSomething

class Base
{
virtual func2(void) { printf("base: func2"); }
void DoSomething(void) {printf("base do something"};}
};

class Derived : public Base {
func2(void) { printf("derived: func2"); }
void DoSomething(void) {printf("derived do something");}
};

void main
{

Derived d;
Base *b;
b = (Base *)Derived;
b.func2() : output = derived: func2
b.DoSomething() : output = derived do something
b = Base;//Don''t have to cast it because it is a Base object.
d.func2() : output = base: func2
b.DoSomething() : output = base do something
}

I don''t know if this is correct or not? In these top examples could I also have done
virtual func2(void) { printf("base: func2"); } = 0;?
I still don''t get the abstraction part all all so maybe someone could explain it again? Thanks again.
Braves





Share this post


Link to post
Share on other sites
A big use for virtual functions is something like this: (the syntax might be a bit off, but hopefully you''ll get the idea)

    
class Shape{
public:
virtual void draw(){} = 0;

private:
int x;
int y;
ImageInfo spr;
};

class Square : public Shape{
public:
void draw(){ // code to draw Sqaure here

}
};

class Circle : public Shape{
public:
void draw(){ // code to draw Circle here

}
};


What using a pure virtual function for Shape does is force you to redefine the draw function for each subclass of Shape. In this way, you can have all derived classes inherit some common members from a base class, but in the base class you do not have a specific definition of how to draw a Shape.

In fact, it would even make sense to define a way to draw a ''shape'' because that isn''t specific enough. A shape can be a circle or square or rectangle or triangle or whatever.

Does that make a little more sense? Since you know you want each shape to be able to draw itself, each subclass is required to create and use it''s own version of draw().

Hope that clears some things up. (Or at least doesn''t make it worse )

Share this post


Link to post
Share on other sites
It''s hard to understand how powerful polymorphism (derived classes with virtual functions) is without a real world example, so here goes. Warning, this might be long

Say you are writing program that the user will need different kinds of shapes (square, circle, triangle, etc) that you will keep in an array. These shapes need to be created, drawn, and printed. You could go about it by creating 3 different classes, one for each shape:

class Square
{
public:
void Create();
void Draw();
void Print();
};

class Circle
{
public:
void Create();
void Draw();
void Print();
};

class Triangle
{
public:
void Create();
void Draw();
void Print();
};

This is all fine and dandy, except you will need 3 different arrays, one for each class type. You could go a different route and create one class that contains all shapes as so:

class Shape
{
public:
void CreateSquare();
void DrawSquare();
void PrintSquare();

void CreateCircle();
void DrawCircle();
void PrintCircle();

void CreateTriangle();
void DrawTriangle();
void PrintTriangle();
};

Now you can include all shapes in one array. However you will need a type variable stating what kind of shape it is so you know what functions to call, plus you''ll have extra variables needed for every shape, in every single instance. A big waste of memory. Let''s look at a 3rd choice:

class Shape
{
public:
virtual void Create() = 0;
virtual void Draw() = 0;
virtual void Print() = 0;
};

class Square : public Shape
{
public:
virtual void Create();
virtual void Draw();
virtual void Print();
};

class Circle : public Shape
{
public:
virtual void Create();
virtual void Draw();
virtual void Print();
};

class Triangle : public Shape
{
public:
virtual void Create();
virtual void Draw();
virtual void Print();
};


We added a 4th class here, called Shape. This is an abstract class, meaning you can''t declare an instance of it. And there would be no reason too either, because it is too generic to be of any use. Now, this is where it gets interesting. You can declare a square as so:

Shape *mysquare = new Square;

Why not just declare it as Square mysquare; you ask? Simple. With the first approach you can put ALL shapes in the same array. Just create the array of type: Shape*, for example:

Shape *myarray[3];

Shape *mysquare = new Square;
Shape *mycircle = new Circle;
Shape *mytriangle = new Triangle;

myarray[0] = mysquare;
myarray[1] = mycircle;
myarray[2] = mytriangle;

Since myarray accepts type Shape*, and the base class of each shape is Shape*, they can all be grouped together. Now, if you need to draw all the shapes, you can do it like thus:

for (int x = 0; x < TOTAL_SHAPES; x++)
myarray[x]->Draw();

What this will do, is call the appropriate draw function for each shape! You as the programmer are oblivious as to what shape those might be, but the program knows and the correct draw function for each shape will be called. Pretty spiffy, eh?

For games, for example, you could create an abstract class Monster, and derive Ogre, Grunt, Werewolf, from them and keep all monsters in the same array/linked list.

There are of course other cool uses and reason for using classes/polymorphism, but I think this is long enough =)

Hope it helped!

Share this post


Link to post
Share on other sites
OMG, someone beat me to it, using my own classes! Copycat!

well, at any rate I think he'll get the idea now =)

BTW, to answer your other question. If you delcare the same function in your base and derived class, and it isn't virtual, it calls the function that you have typecast the variable to. Using my previous example, lets say that we declared void Draw as a NON virtual function. In the for loop:

for (int x = 0; x < TOTAL_SHAPES; x++)
myarray[x]->Draw();

It would call the Shapes Draw function, because it was declared as Shape*. It can also be typecasted it to call whichever function you wish:

((Shape*)myarray[0])->Draw(); // This calls Shape's draw function
((Square*)myarray[0])->Draw(); // This calls Square's draw function

But obviously you need to know WHAT kind of object it really is to call the correct function. Any non-pointer variable declaration like so:

Square mysquare;

will always call Square's functions, unless typecasted to tell it otherwise.


Edited by - Houdini on August 29, 2000 1:35:43 PM

Share this post


Link to post
Share on other sites
quote:
Original post by Houdini

OMG, someone beat me to it, using my own classes! Copycat!

well, at any rate I think he''ll get the idea now =)


I guess we both read the same book or something. haha

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!