Vritual Functions

Started by
3 comments, last by Demerdar 20 years, 6 months ago
What''s the point of a virtual and pure virtual function? Sorry for sounding so niave.
Advertisement
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]
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
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...
_______________________________________Understanding is a three edged sword...Freelance Games - Home of XBLIG Starchonwww.FreelanceGames.com
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 functionclass Monster{public:   virtual void DoAI()   { cout << "Monster::DoAI()" << endl; };};/////////////////////////////////////////////////////////////////// Derived Grunt class which re-defines the virtual functionclass 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]
I asked some questions about virtual functions recently; you might want to check out this thread for more information on virtual functions, and some of their uses.
Peon

This topic is closed to new replies.

Advertisement