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.
sonu yeh tera hai kya bhai
ReplyDeleteNice explanation and example Sonu! Another good one:
ReplyDeletePure virtual function