Thursday, December 27, 2012

C++ : Pure virtual functions and abstract base classes

Pure virtual (abstract) functions and abstract base classes

C++ allows you to create a special kind of virtual function called a pure virtual function (or abstract function) that has no body at all! A pure virtual function simply acts as a placeholder that is meant to be redefined by derived classes.
To create a pure virtual function, rather than define a body for the function, we simply assign the function the value 0. See the example below :-

class XYZ{
    
public:
    
    void init() // A normal non-vitual function
    {
        cout<<"Initialize";
    }
    
    virtual void show() // Normal Virtual Function
    {
        cout<<"Valuse is:- " << 8;
    }
    virtual int getValue() = 0; // A Pure Virtual Function
};
 
When we add a pure virtual function to our class, we are effectively saying, “it is up to the 
derived classes to implement this function”. Using a pure virtual function has two main 
consequences: First, any class with one or more pure virtual functions becomes an abstract 
XYZ class, which means that it can not be instantiated! 

int main()
{
    XYZ xyz; // pretend this was legal
    xyz.getValue(); // what would this do?
}
 
So, we cannot create the object of an abstract class, since the 
compiler doesn't know, how much size does the class object take. 
We simply extend it. 

Second, any derived class must define a body for this function, or that
 derived class will be considered an abstract base class as well.

Let’s take a look at an example of a pure virtual function in action.

#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"; }
};
 
We’ve prevented people from allocating objects of type Animal by making the constructor protected. 
However, there’s one problem that has not been addressed. It is still possible to create derived 
classes that do not redefine Speak(). For example:
 
class Cow: public Animal
{
public:
    Cow(std::string strName): Animal(strName)
    {


    }
// We forgot to redefine Speak
};
int main()
{
    Cow cCow("Betsy");
    std::cout << cCow.GetName() << " says " << cCow.Speak() << "\n";
}

This will print: Betsy says ???
What happened? We forgot to redefine Speak, so cCow.Speak() resolved to Animal. Speak(), 
which isn’t what we wanted.A better solution to this problem is to use a pure virtual 
function: 

#include <string>
class Animal
{
protected:
    std::string m_strName;
public:
    Animal(std::string strName):m_strName(strName)
    {


    }
    std::string GetName() { return m_strName; }
    virtual const char* Speak() = 0; // pure virtual function
}; 
 
There are a couple of things to note here. First, Speak() is now a pure virtual function. 
This means Animal is an abstract base class, and can not be instantiated. Consequently, 
we do not need to make the constructor protected any longer (though it doesn’t hurt). Second, 
because our Cow class was derived from Animal, but we did not define Cow::Speak(), Cow is also 
an abstract base class. Now when we try to 
compile this code:
 
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() = 0;
};


class Cow: public Animal
{
public:
    Cow(std::string strName): Animal(strName)
    {


    }
// We forgot to redefine Speak
};
int main()
{
    Cow cCow("Betsy");
    std::cout << cCow.GetName() << " says " << cCow.Speak() << "\n";
}
 
The compiler will give us a warning because Cow is an abstract base class and we can not 
create instances of abstract base classes:
 
error: C2259: 'Cow' : cannot instantiate abstract class
due to following members:
'const char *Animal::Speak(void)' : is abstract 

This tells us that we will only be able to instantiate Cow if Cow provides a body for Speak(). 
Let’s go ahead and do that:

class Cow: public Animal
{
public:
    Cow(std::string strName)
    : Animal(strName)
    {
    }
    virtual const char* Speak() { return "Moo"; }
};
int main()
{
    Cow cCow("Betsy");
    std::cout << cCow.GetName() << " says " << cCow.Speak() << endl;
}
 
Now this program will compile and print:
"Betsy says Moo"
So, A pure virtual function is useful when we have a function that we want to put in the base class,
but only the derived classes know what it should return. A pure virtual function makes it so the base 
class can not be instantiated, and the derived classes are forced to define these function before 
they can be instantiated. This helps ensure the derived classes do not forget to redefine functions 
that the base class was expecting them to.
 
For interface classes, Check this link.

2 comments: