The Differences Between Virtual and Pure Virtual Functions in C++
This article will describe the differences between virtual and pure virtual functions in C++.
Virtual Functions and Their Characteristics in C++
Virtual functions are closely associated with the concept of polymorphism. In C++, we can organize different classes in a linked hierarchy where they might be sharing some data members and having the same member functions exposed as the interface.
Generally, the classes that inherit some part of code from other classes are called derived classes, whereas the ones inherited from are the base classes. Note that sometimes these terms may be interchangeably used with parent-child or superclass-subclass names. The functions that can be overridden in derived classes are called virtual functions, and they are declared with the keyword virtual
. Virtual functions have the same name within the given class hierarchy, and every derived class can implement its own definition of the function.
If the function is not overridden, the derived class object invokes the function defined in the base class. The following example program below demonstrates the basic usage of virtual functions by defining the print
function in both the Engineer
and Employee
classes. Then we can implement some arbitrary function Func
that accepts the reference to Employee
and calls the print
function within the body.
Now, the Func
implementation may change multiple times, but it will always call the corresponding print
function based on the object that’s being passed as the parameter. We can add multiple derived classes in the Employee
class hierarchy. Each of them may/may not implement the print
function, but the Func
function will accept their instances and invoke the correct virtual function.
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
class Employee {
public:
Employee(string fn, string ln)
: first_name(std::move(fn)), last_name(std::move(ln)) {}
virtual void print() {
cout << "name: " << first_name << "\n"
<< "last name: " << last_name << "\n";
};
protected:
string first_name, last_name;
};
class Engineer : public Employee {
public:
Engineer(string fn, string ln, string sp)
: Employee(std::move(fn), std::move(ln)), specialization(std::move(sp)) {}
void print() override {
Employee::print();
cout << "specialization: " << specialization << "\n";
}
private:
string specialization;
};
void Func(Employee &em) { em.print(); }
int main() {
Employee em1("Jim", "Jiao");
Engineer eng1("Jin", "Baker", "Aerospace Engineering");
Func(em1);
cout << "\n";
Func(eng1);
return EXIT_SUCCESS;
}
Output:
name: Jim
last name: Jiao
name: Jin
last name: Baker
specialization: Aerospace Engineering
Pure Virtual Functions and Abstract Types in C++
On the other hand, we have the concept of pure virtual functions, which are declared similar to the regular virtual functions and include the notation = 0;
at the end of the declaration. These functions essentially don’t have a definition in the base class, where they are declared first. Thus, they will be most likely defined in the derived classes.
The classes containing pure virtual functions are called abstract classes, and they are usually utilized to specify the interface for the derived classes. Note that abstract classes can not be directly instantiated.
The next code snippet implements the Triangle
and Rectangle
classes with the abstract base class Shape
. In this case, we defined the printArea
pure virtual function in both derived classes. Sometimes, a derived class might not define an inherited pure virtual function, making it another abstract class in the given class hierarchy. A derived class may inherit multiple pure virtual functions. If it does not define even one of them, abstract classification is applied to the class.
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::endl;
using std::string;
using std::vector;
class Shape {
public:
virtual void printArea() = 0;
};
class Triangle : public Shape {
public:
Triangle(double b, double h) : base(b), height(h) {}
void printArea() override { cout << (base * height) / 2.0; }
private:
double base;
double height;
};
class Rectangle : public Shape {
public:
Rectangle(double i1, double i2) : edges({i1, i2}) {}
void printArea() override { cout << edges[0] * edges[1]; }
private:
vector<double> edges;
};
int main() {
Triangle t1(3, 5);
t1.printArea();
cout << "\n";
Rectangle r1(3, 5);
r1.printArea();
cout << "\n";
return EXIT_SUCCESS;
}
Output:
7.5
15
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook