virtual functions in C++
In C++, a virtual function is a function in the base class that is declared using the virtual
keyword and is intended to be overridden in derived classes. The purpose of virtual functions is to enable runtime polymorphism, where the function that is called depends on the actual object type (not the type of the pointer or reference used to call it).
Virtual functions are a key feature in object-oriented programming (OOP) because they allow the behavior of derived classes to be invoked through base class pointers or references. This allows you to write more flexible and reusable code, especially in scenarios where the actual object type may not be known at compile-time.
A virtual function in the base class is one that can be overridden in a derived class to provide a custom implementation. When a base class pointer or reference is used to call the function, C++ uses dynamic dispatch (or late binding) to determine which function to call, based on the actual type of the object being pointed to, rather than the type of the pointer or reference.
class BaseClass {
public:
virtual void functionName() {
// Base class implementation
}
};
virtual
keyword is used to declare a function as virtual in the base class.Let's see how virtual functions work in practice with an example:
#include <iostream>
using namespace std;
class Animal {
public:
virtual void sound() { // Virtual function
cout << "Animal makes a sound!" << endl;
}
};
class Dog : public Animal {
public:
void sound() override { // Overriding the virtual function
cout << "Dog barks!" << endl;
}
};
class Cat : public Animal {
public:
void sound() override { // Overriding the virtual function
cout << "Cat meows!" << endl;
}
};
int main() {
Animal* animal1 = new Dog(); // Base class pointer, but object is of type Dog
Animal* animal2 = new Cat(); // Base class pointer, but object is of type Cat
animal1->sound(); // Output: Dog barks!
animal2->sound(); // Output: Cat meows!
delete animal1;
delete animal2;
return 0;
}
Explanation:
sound()
function is declared as virtual
in the Animal
base class.Dog
and Cat
classes override the sound()
function to provide their specific implementations.animal1
and animal2
are pointers of type Animal*
, the appropriate version of sound()
is called at runtime, based on the type of object (Dog
or Cat
) they are pointing to. This is runtime polymorphism in action.A common use of virtual functions is for destructors. If you have a class hierarchy where objects are dynamically allocated, and you are using base class pointers to delete derived class objects, you need to ensure that the correct destructor is called. This is done by declaring the destructor in the base class as virtual.
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() { // Virtual destructor
cout << "Base class destructor" << endl;
}
};
class Derived : public Base {
public:
~Derived() override { // Overriding the destructor
cout << "Derived class destructor" << endl;
}
};
int main() {
Base* ptr = new Derived();
delete ptr; // Correct destructor called due to virtual destructor
return 0;
}
Explanation:
Base
class is declared virtual
, deleting a Derived
class object through a Base*
pointer will call the Derived
class destructor first, followed by the Base
class destructor. This ensures that all resources allocated by the derived class are properly cleaned up.Base
class were not virtual, only the Base
class destructor would be called, potentially causing a resource leak in the derived class.A pure virtual function is a function that is declared in the base class, but has no implementation. It makes the base class abstract, meaning you cannot instantiate objects of that class directly. Derived classes are required to provide an implementation for pure virtual functions.
class Base {
public:
virtual void functionName() = 0; // Pure virtual function
};
= 0
at the end of the function declaration.
#include <iostream>
using namespace std;
class Shape {
public:
virtual void draw() = 0; // Pure virtual function
};
class Circle : public Shape {
public:
void draw() override { // Override pure virtual function
cout << "Drawing a circle!" << endl;
}
};
class Square : public Shape {
public:
void draw() override { // Override pure virtual function
cout << "Drawing a square!" << endl;
}
};
int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Square();
shape1->draw(); // Output: Drawing a circle!
shape2->draw(); // Output: Drawing a square!
delete shape1;
delete shape2;
return 0;
}
Explanation:
Shape
class is abstract because it contains a pure virtual function draw()
.Circle
and Square
classes provide their own implementations of the draw()
function.Shape
pointers or references, but ensures that the actual object type determines the specific behavior at runtime.You should use virtual functions when: