Archived

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

Vritual Functions

This topic is 5183 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

Suppose you have a base class and two derived classes...


class Animal
{
public:
virtual void MakeNoise() { return; }
};

class Cow
{
public:
void MakeNoise() { MakeMooSound(); }
};

class Dog
{
public:
void MakeNoise() { MakeBarkSound(); }
};



That should be fairly simple. Now let's first pretend that the MakeNoise function in class Animal isn't virtual. If you have this code:

void MakeNoise( Animal a )
{
a.MakeNoise();
}

If you passed an Animal to this function, it would call Animal's MakeNoise. Now if you passed a derivative of Animal, for example, Cow, then it would call Animal's MakeNoise, not Cow's MakeNoise!

By making the function virtual, I guarantee that the correct child function is called, even when I cast upwards to the parent. In general, any function that could be overridden by children should be virtual.

Now suppose we change the class Animal definition to this:

class Animal
{
public:
virtual void MakeNoise() = 0;
};


Notice that this time there is no implementation, and I use = 0. This is called a pure virtual function. A pure virtual function has no implementation. More importantly, a class with pure virtual functions can't be instantiated. You have to derive a class from it, and override MakeNoise, at which point it will be virtual. It's important to realise that even thouse you can't instantiate an Animal like this, you can still use it--it just has to be cast from Dog or Cow, not directly created as an Animal , i.e. you can't use a = new Animal; because Animal can't be created, but you can use a = new Dog();.

[edited by - Promit on October 10, 2003 6:16:04 PM]

Share this post


Link to post
Share on other sites
A class is considered to be pure if it contains one or more pure virtual functions. However, this does not mean that all the functions in a pure class have to be pure. Generally, pure functions are used to in the creation of an abstract interface where the developer wants to make sure that all concrete classes adhere to the common interface. Furthermore, it helps to foster good design by allowing for the creation of a concrete to abstract association in the object model.


Understanding is a three edged sword...

Share this post


Link to post
Share on other sites
In general, if we call a virtual function on a base class pointer that points to a derived class object, then the derived class's definition of the virtual function will be called (that is if the derived class has actually defined the virtual function). This is called dynamic binding, because the type of the object that the base class pointer points to is unknown at runtime (The pointer could point to a object of a derived class, since derived class objects are type compatible with base class objects, hence the "IS A" relationship of public inheritance).

Here's an example of using virtual functions.


/////////////////////////////////////////////////////////////////

// Base class which declares a virtual function

class Monster
{
public:
virtual void DoAI() { cout << "Monster::DoAI()" << endl; };
};

/////////////////////////////////////////////////////////////////

// Derived Grunt class which re-defines the virtual function

class Grunt : public Monster
{
public:
void DoAI() { cout << "Grunt::DoAI()" << endl; };
};
/////////////////////////////////////////////////////////////////



Here we declare a pointer to base class which actually points to a Grunt object. Remember this is allowed since derived class objects are type compatible with base class objects (but not vise versa).

Monster* pMonster = new Grunt;

When we call the DoAI() member function it is unknown at compile time what exact type of object pMonster actually points to, even though we declared the type as pointer-to-Monster. Since the DoAI() function is virtual, the correct DoAI() function will be called depending on what type of object pMonster actually points to. If we didn't declare the DoAI() function as virtual, then we wouldn't get this dynamic behaviour, and the compiler would assume that the actual object that pMonster points to is a Monster (but this isn't true). This is called "Static Binding", as opposed to "Dynamic Binding". You can imagine the virtual keyword in a member function declaration as an indicator of whether we want dynamic behaviour or static behaviour for that particular member function.

pMonster->DoAI(); // In this example, this calls Grunt::DoAI()

Pure virtual functions are simply virtual functions that are declared but not defined in a base class. Classes that contain at least one pure virtual function are called Abstract Base Classes (ABC for short). You cannot call pure virtual functions, doing so will cause a compiler error. To declare a pure virtual function, you simply append '= 0' at the end of the function declaration:


// This class declares a pure virtual function that

// will not be defined, therefore making this class

// an 'Abstract Base Class'.

class C
{
public:
virtual void PureVirtualFunc() = 0;
};


Virtual functions are hard to explain and hard to grasp, it takes a lot of reading and experimenting to understand them. Don't worry though, it will eventually click in your head!

[edited by - chacha on October 11, 2003 4:59:51 AM]

Share this post


Link to post
Share on other sites