Navigation



12.2 — Virtual functions

In the previous lesson on pointers and references to the base class of derived objects, we took a look at a number of examples where using pointers or references to a base class had the potential to simplify code. However, in every case, we ran up against the problem that the base pointer or reference was only able to call the base version of a function, not a derived version.

Here’s a simple example of this behavior:

class Base
{
protected:

public:
    const char* GetName() { return "Base"; }
};

class Derived: public Base
{
public:
    const char* GetName() { return "Derived"; }
};

int main()
{
    Derived cDerived;
    Base &rBase = cDerived;
    cout << "rBase is a " << rBase.GetName() << endl;
}

This example prints the result:

rBase is a Base

Because rBase is a Base pointer, it calls Base::GetName(), even though it’s actually pointing to the Base portion of a Derived object.

In this lesson, we will address this issue using virtual functions.

Virtual functions

A virtual function is a special type of function that resolves to the most-derived version of the function with the same signature. To make a function virtual, simply place the “virtual” keyword before the function declaration.

Note that virtual functions and virtual base classes are two entirely different concepts, even though they share the same keyword.

Here’s the above example with a virtual function:

class Base
{
protected:

public:
    virtual const char* GetName() { return "Base"; }
};

class Derived: public Base
{
public:
    virtual const char* GetName() { return "Derived"; }
};

int main()
{
    Derived cDerived;
    Base &rBase = &cDerived;
    cout << "rBase is a " << rBase.GetName() << endl;

    return 0;
}

This example prints the result:

rBase is a Derived

Because rBase is a pointer to the Base portion of a Derived object, when rBase.GetName() is evaluated, it would normally resolve to Base::GetName(). However, Base::GetName() is virtual, which tells the program to go look and see if there are any more-derived versions of the function available. Because the Base object that rBase is pointing to is actually part of a Derived object, the program will check every inherited class between Base and Derived and use the most-derived version of the function that it finds. In this case, that is Derived::GetName()!

Let’s take a look at a slightly more complex example:

class A
{
public:
    virtual const char* GetName() { return "A"; }
};

class B: public A
{
public:
    virtual const char* GetName() { return "B"; }
};

class C: public B
{
public:
    virtual const char* GetName() { return "C"; }
};

class D: public C
{
public:
    virtual const char* GetName() { return "D"; }
};

int main()
{
    C cClass;
    A &rBase = cClass;
    cout << "rBase is a " << rBase.GetName() << endl;

    return 0;
}

What do you think this program will output?

Let’s look at how this works. First, we instantiate a C class object. rBase is an A pointer, which we set to point to the A portion of the C object. Finally, we call rBase.GetName(). rBase.GetName() evaluates to A::GetName(). However, A::GetName() is virtual, so the compiler will check all the classes between A and C to see if it can find a more-derived match. First, it checks B::GetName(), and finds a match. Then it checks C::GetName() and finds a better match. It does not check D::GetName() because our original object was a C, not a D. Consequently, rBase.GetName() resolves to C::GetName().

As a result, our program outputs:

rBase is a C

A more complex example

Let’s take another look at the Animal example we were working with in the previous lesson. Here’s the original class:

#include <string>
class Animal
{
protected:
    std::string m_strName;

    // We're making this constructor protected because
    // we don't want people creating Animal objects directly,
    // but we still want derived classes to be able to use it.
    Animal(std::string strName)
        : m_strName(strName)
    {
    }

public:
    std::string GetName() { return m_strName; }
    const char* Speak() { return "???"; }
};

class Cat: public Animal
{
public:
    Cat(std::string strName)
        : Animal(strName)
    {
    }

    const char* Speak() { return "Meow"; }
};

class Dog: public Animal
{
public:
    Dog(std::string strName)
        : Animal(strName)
    {
    }

    const char* Speak() { return "Woof"; }
};

And here’s the class with virtual functions:

#include <string>
class Animal
{
protected:
    std::string m_strName;

    // We're making this constructor protected because
    // we don't want people creating Animal objects directly,
    // but we still want derived classes to be able to use it.
    Animal(std::string strName)
        : m_strName(strName)
    {
    }

public:
    std::string GetName() { return m_strName; }
    virtual const char* Speak() { return "???"; }
};

class Cat: public Animal
{
public:
    Cat(std::string strName)
        : Animal(strName)
    {
    }

    virtual const char* Speak() { return "Meow"; }
};

class Dog: public Animal
{
public:
    Dog(std::string strName)
        : Animal(strName)
    {
    }

    virtual const char* Speak() { return "Woof"; }
};

Note that we didn’t make Animal::GetName() virtual. This is because GetName() is never overridden in any of the derived classes, therefore there is no need.

Now, using the virtual Speak() function, the following function should work correctly:

void Report(Animal &rAnimal)
{
    cout << rAnimal.GetName() << " says " << rAnimal.Speak() << endl;
}

int main()
{
    Cat cCat("Fred");
    Dog cDog("Garbo");

    Report(cCat);
    Report(cDog);
}

Indeed, this program produces the result:

Fred says Meow
Garbo says Woof

When cAnimal.Speak() is evaluated, the program notes that it is a virtual function. In the case where rAnimal is pointing to the Animal portion of a Cat object, the program looks at all the classes between Animal and Cat to see if it can find a more derived function. In that case, it finds Cat::Speak(). In the case where rAnimal points to the Animal portion of a Dog object, the program resolves the function call to Dog::Speak().

Similarly, the following array example now works as expected:

Cat cFred("Fred"), cTyson("Tyson"), cZeke("Zeke");
Dog cGarbo("Garbo"), cPooky("Pooky"), cTruffle("Truffle");

// Set up an array of pointers to animals, and set those pointers to our Cat and Dog objects
Animal *apcAnimals[] = { &cFred, &cGarbo, &cPooky, &cTruffle, &cTyson, &cZeke };
for (int iii=0; iii < 6; iii++)
    cout << apcAnimals[iii]->GetName() << " says " << apcAnimals[iii]->Speak() << endl;

Which produces the result:

Fred says Meow
Garbo says Woof
Pooky says Woof
Truffle says Woof
Tyson says Meow
Zeke says Meow

Even though these two examples only use Cat and Dog, any other classes we derive from Animal would also work with our Report() function and Animal array without further modification! This is perhaps the biggest benefit of virtual functions — the ability to structure your code in such a way that newly derived classes will automatically work with the old code without modification!

A word of warning: the signature of the derived class function must exactly match the signature of the base class virtual function in order for the derived class function to be used. If the derived class function has different parameter types, the program will likely still compile fine, but the virtual function will not resolve as intended.

Use of the virtual keyword

Technically, the virtual keyword is not needed in derived class. For example:

class Base
{
protected:

public:
    virtual const char* GetName() { return "Base"; }
};

class Derived: public Base
{
public:
    const char* GetName() { return "Derived"; } // note lack of virtual keyword
};

int main()
{
    Derived cDerived;
    Base &rBase = cDerived;
    cout << "rBase is a " << rBase.GetName() << endl;

    return 0;
}

prints

rBase is a Derived

Exactly the same as if Derived::GetName() was explicitly tagged as virtual. Only the most base class function needs to be tagged as virtual for all of the derived functions to work virtually. However, having the keyword virtual on the derived functions does not hurt, and it serves as a useful reminder that the function is a virtual function rather than a normal one. Consequently, it’s generally a good idea to use the virtual keyword for virtualized functions in derived classes even though it’s not strictly necessary.

Return types of virtual functions

Under normal circumstances, the return type of a virtual function and it’s override must match. Thus, the following will not work:

class Base
{
public:
    virtual int GetValue() { return 5; }
};

class Derived: public Base
{
public:
    virtual double GetValue() { return 6.78; }
};

However, there is one special case in which this is not true. If the return type of a virtual function is a pointer or a reference to a class, override functions can return a pointer or a reference to a derived class. These are called covariant return types. Here is an example:

class Base
{
public:
    // This version of GetThis() returns a pointer to a Base class
    virtual Base* GetThis() { return this; }
};

class Derived: public Base
{
    // Normally override functions have to return objects of the same type as the base function
    // However, because Derived is derived from Base, it's okay to return Derived* instead of Base*
    virtual Derived* GetThis() { return this; }
};

Note that some older compilers (eg. Visual Studio 6) do not support covariant return types.

12.3 — Virtual destructors, virtual assignment, and overriding virtualization
Index
12.1 — Pointers and references to the base class of derived objects

34 comments to 12.2 — Virtual functions

  • Ray
    Base &rBase = &cDerived;

    Hi can you explain whats is going on with this line… I’m following well, thx for the tut’s! :) just wondering if the first ampersand is meant to be there…?

    [ It was a typo. The line has been fixed. Thanks for noticing! -Alex ]

  • [...] 2007 Prev/Next Posts « Break Time — Saint Petersburg | Home | 12.2 — Virtual functions » Tuesday, January 29th, 2008 at 3:45 [...]

  • Steve Checkoway

    Your claim that if the derived class’s function’s return type differs from the function it is overriding, then the virtual function will not resolve as intended. This is incorrect. A function’s return type is not part of its signature. Doing something like the following is actually quite helpful:

    #include
    struct Base
    {
    virtual ~Base() { }
    virtual Base *Copy() const
    {
    puts( “Base::Copy()” );
    return new Base(*this);
    }
    };

    struct Derived : public Base
    {
    Derived *Copy() const
    {
    puts( “Derived::Copy()” );
    return new Derived(*this);
    }
    };

    int main()
    {
    Derived d;
    Base &b = d;
    Base *b2 = b.Copy();
    Base *b3 = d.Copy();
    Derived *d2 = d.Copy();
    Derived *d3 = dynamic_cast( b.Copy() );

    delete b2;
    delete b3;
    delete d2;
    delete d3;
    return 0;
    }

    The four calls to Copy() will all call Derived::Copy() (as you can see by running the code). This is useful when you need to make full copies of objects and all you have is a Base *.

    Edit: This is ignoring the <pre> tags and I don’t feel like formatting it using HTML in the 2.5 minutes I have left.

  • [...] 2007 Prev/Next Posts « 12.2 — Virtual functions | Home | 12.4 — Early binding and late binding » Friday, February 1st, 2008 at 1:50 [...]

  • Ben

    Hi Alex,
    in your all your classes, whether they are derived, or base classes, you put the virtual keyword in front of the function definition of every function which shall be overwritten in the derived class, even though this is not necessary in the derived class – as long there is no class, which inherits from that, which shall overwrite the function again. It would be clearing, to point out, that it is not necessary.
    Ben

  • Suman

    Hi,

    I am getting the following error while compiling on linux.
    sushils)@linux1:(~/test/test++)
    $ g++ virtualInheritance.cc
    virtualInheritance.cc: In function `int main()’:
    virtualInheritance.cc:20: conversion from `Derived*’ to non-scalar type `Base’
    requested
    virtualInheritance.cc:20: cannot initialize `Base&’ from `Derived*’
    virtualInheritance.cc:21: `cout’ undeclared (first use this function)
    virtualInheritance.cc:21: (Each undeclared identifier is reported only once for
    each function it appears in.)
    virtualInheritance.cc:21: `endl’ undeclared (first use this function)
    sushils)@linux1:(~/test/test++)

    $ cat virtualInheritance.cc
    #include <iostream>
    
    class Base
    {
    protected:
    
    public:
        virtual const char* GetName() { return "Base"; }
    };
    
    class Derived: public Base
    {
    public:
        virtual const char* GetName() { return "Derived"; }
    };
    
    int main()
    {
        Derived cDerived;
        Base &rBase = &cDerived;
        cout << "rBase is a " << rBase.GetName() << endl;
    
        return 0;
    }
    

    Thanks in advance
    With regards
    Sushil

  • prabodh

    can we write “visiblity mode base class name virtual keyword” ?
    while deriving new class from base class decleartion……..

  • manju23reddy

    hi the below code gets core dump y and how to solve it so that i should set base object with derived pointer in get function only and use rBase in main to call a function of those classes.

    #include <iostream>
    #include <conio.h>
    #include <iostream>
    
    class Base
    {
    protected:
    
    public:
        virtual const char* GetName() { return "Base"; }
    };
    
    class Derived: public Base
    {
    public:
        virtual const char* GetName() { return "Derived"; }
    };
    
    void get(Base *rBase)
    {
       Derived *cDerived = new Derived();
       rBase = cDerived;
    }
    int main()
    {
        Base *rBase = NULL;
        std::cout << "rBase is a " << rBase->GetName() << "\n";
        getch();
        return 0;
    }
    
    • ray
      void get(Base *&rBase)
      {
         Derived *cDerived = new Derived();
         rBase = cDerived;
      }
      int main()
      {
          Base *rBase = NULL;
          get(rBase);
          std::cout << "rBase is a " << rBase->GetName() << "\n";
          getch();
          return 0;
      }
      
  • Hallo all!

    Urm, this is going to sound really stupid, so I’m sorry for my ignorance.

    But why don’t we just use a pointer type of the derived class? It seems that the main reason for virtual functions is that we are using a pointer from the base class instead of the derived.

    EDIT;

    Ah! wait a min!! So say you have a pointer of the animal base type, you might want to point that to the derived classes of say Dolphin, Elephant, Human etc…. so rather than creating a pointer for each derived you just create one base class pointer and use that with virtual functions. right?

  • Lavanya

    hi all,

    I was looking for a solution to the below problem. Can someone please help?

    I’m given this statement Base * b = new Derived;
    just this line.
    I know that Both base and derived classes have a virtual (overidden in derived) function called Fun().

    Given only the above line, how do i invoke base’s Fun(), instead of Derived’s Fun().

    Would appreciate any responses.

  • Rami

    is there a performance penalty by using virtual functions? If not then all functions should be virtual functions, no harm right?! =D

  • Steve

    I’m sorry but you lost me here.

    Why do u p.e. use “virtual const char* GetName() { return “A”; }”?

    Why are u using a const pointer as return value? I have run the example with a normal pointer as return, and it ran the same?

    Thx

  • Steve

    Sorry I mean a pointer to a const …

  • Steve

    Never mind, I figured it out.

    The solution was if there was no pointer to a const (const char*), the user would be able to do this:

    rBase.GetName()[0] = ‘a’;

    which would cause an access violation exception at runtime.

  • auasp

    one extra ‘&’ in line number 18 of 2nd code listing

  • Hello Alex,

    Wonderful explanations all around.
    Way better than most textbooks.

    Only one point that has confused the daylights out of me.

    
    15. int  main()
    16. {
    17.    Derived cDerived;
    18.    Base &rBase = &cDerived;
    19.    cout << "rBase is a " << rBase.GetName() << endl;
    20.
    21.    return 0; }
    

    I believe rBase is a “reference”, not a “pointer.”
    if it were

    18.    Base *rBase = &cDerived;
    

    Then it would be a pointer.

    Thanks!

    Raj

  • sss

    Hi Alex,

    Can you tell me conceptually why the need of virtual functions came into picture? i do understand the concept but what is the necessity, just to reduce overhead ..but calling virtual function itself is an overhead????

  • Mystic

    Use of the virtual keyword

    Technically, the virtual keyword is not needed in derived class. For example:

    class Base
    {
    protected:
    
    public:
        virtual const char* GetName() { return "Base"; }
    };
    
    class Derived: public Base
    {
    public:
        const char* GetName() { return "Derived"; } // note lack of virtual keyword
    };
    
    int main()
    {
        Derived cDerived;
        Base &rBase = cDerived;
        cout << "rBase is a " << rBase.GetName() << endl;
    
        return 0;
    }

    prints

    rBase is a Derived

    What would happen if it was changed to include something like:

    class DerivedTwice: public Derived
    {
    public:
        const char* GetName() { return "DerivedTwice"; }
    };
    
    int main()
    {
        DerivedTwice cDerivedTwice;
        Derived &rDerived = cDerivedTwice;
        cout << "rDerived is a " << rDerived.GetName() << endl;
    
        return 0;
    }
    

    ? Then wouldn’t it say “rDerived is a ‘Derived’” instead of “rDerived is a ‘DerivedTwice”? That’s not what you’d want… You might want to say something to that effect (if that actually happens, I haven’t checked my code).

    • D.M. Ryan

      The odd thing is, when I tried your code I got “rDerived is a DerivedTwice”. [I compiled it using Visual Studio 2005.] I thought a second virtual keyword would be needed to get that output, but it isn’t. For VS2005, at least, it’s only necessary for the virtual keyword to be at the base; virtual carries through all the way down the inheritance chin.

      To be specific, this code:

      class Base
      {
      protected:
      
      public:
          virtual const char* GetName() { return "Base"; } // virtual keyword here
      };
      
      class Derived: public Base
      {
      public:
         const char* GetName() { return "Derived"; } // note lack of virtual keyword here
      };
      
      class DerivedTwice: public Derived
      {
      public:
          const char* GetName() { return "DerivedTwice"; }
      };
      
      int main()
      {
          DerivedTwice cDerivedTwice;
          Derived &rDerived = cDerivedTwice;
          cout << "rDerived is a " << rDerived.GetName() << endl; // outputs "rDerived is a DerivedTwice"
                                                                  // despite lack of second virtual keyword.
      
          return 0;
      }

      outputs the “rDerived is a DerivedTwice” being looked for, when compiled with VS’05. Other compilers might require the second keyword.

  • Ravi Gautam

    Hi,

    why are we using &rBase instead of rBase?

    I have read the chapter on reference but still can’t figure it out.

    Please do reply.

You must be logged in to post a comment.