Home

 › 

Articles

 › 

Understanding Virtual Base Class In C++, With Examples

web developer programming software engineer PC computer monitor

Understanding Virtual Base Class In C++, With Examples

Virtual base classes are an essential feature in C++, as well as other object-oriented programming (OOP) languages. They’re used to help achieve polymorphism by preventing ambiguity errors; specifically, what’s known as the “diamond problem.” If you’re wondering what virtual base classes in C++ are and how they work, we’re going to dig into it here.

What Are Virtual Base Classes in C++?

You may think virtual base classes are the same thing as virtual functions. They do share some similarities, in that they help enable dynamic behavior and are declared using the virtual keyword, but there are key differences.

While virtual functions are used so they can be overridden by derived classes, virtual base classes are designed to be shared among all derived classes. This makes sure that only one instance of the base class is shared among the derived classes, which is crucial in preventing the diamond problem.

What Is the Diamond Problem?

You’re likely familiar with the general shape of a diamond. Unsurprisingly, this is where the diamond problem gets its name. Let’s consider 4 classes, named 1 to 4, respectively. Class 1 is the parent class, and is inherited by classes 2 and 3.

These are, in turn, inherited by class 4. This leads to class 1 being inherited multiple times by class 4 since classes 2 and 3 had already inherited from class 1. Therefore, we encounter a problem where multiple instances exist, and an ambiguity error is produced.

This is because the compiler can’t decide which instance of the class to execute. This is prevented by using virtual base classes, as only a single copy is shared.

For example, consider this code block:

#include <iostream>

class Animal {
public:
    void breathe() {
        std::cout << "Animal is breathing." << std::endl;
    }
};

class Mammal : public Animal {
public:
    void eat() {
        std::cout << "Mammal is eating." << std::endl;
    }
};

class Bird : public Animal {
public:
    void fly() {
        std::cout << "Bird is flying." << std::endl;
    }
};

class Bat : public Mammal, public Bird {
public:
    void navigate() {
        std::cout << "Bat is navigating." << std::endl;
    }
};

int main() {
    Bat bat;
    bat.breathe();
    return 0;
}

Here, we’ve declared the base “Animal” class, with derived classes “Mammal” and “Bird.” In turn, the “Bat” class is derived from both “Mammal” and “Bird.” Each of these classes is intended to print a message upon calling a specific function.

However, because “Bat” inherits multiple instances of “Animal” through “Mammal” and “Bird,” when we call the “breathe()” function, the compiler is unable to determine which function to call. This results in an ambiguity error, which can be seen in the image below.

virtual base class in c++
Causing an ambiguity error.

How Are Virtual Base Classes in C++ Used?

As previously mentioned, virtual base classes are declared using the virtual keyword. The general syntax is:

class Base {
};

class Derived : virtual public Base {
};

Where “Base” is the base class, and “Derived” is the derived class. Counterintuitively, the virtual keyword is used in the declaration of the derived class, rather than the base class. The keyword is also only used in the class that directly inherits from the base class, not all subsequent classes.

To illustrate, let’s carry on with our example from earlier. We ran into the diamond problem, but we can resolve this by using a virtual base class:

#include <iostream>

class Animal {
public:
    void breathe() {
        std::cout << "Animal is breathing." << std::endl;
    }
};

class Mammal : virtual public Animal {
public:
    void eat() {
        std::cout << "Mammal is eating." << std::endl;
    }
};

class Bird : virtual public Animal {
public:
    void fly() {
        std::cout << "Bird is flying." << std::endl;
    }
};

class Bat : public Mammal, public Bird {
public:
    void navigate() {
        std::cout << "Bat is navigating." << std::endl;
    }
};

int main() {
    Bat bat;
    bat.breathe();
    return 0;
}

The change here is that we’ve declared the “Animal” class as virtual for both of its directly derived classes. Therefore, the instance is only inherited once, and the breathe() function is no longer ambiguous. We receive the expected output, as seen in the image below.

virtual base class in c++
Getting the expected output.

Wrapping Up

Virtual base classes in C++ are pivotal in preventing the diamond problem, a common ambiguity error. While different from virtual functions, they’re commonly used together.

This can be done to avoid multiple instances of inheritance while allowing each derived class to execute its own implementation. When working with OOP languages, virtual base classes are a very useful tool to have in your arsenal.

Frequently Asked Questions

What's the difference between virtual base classes and virtual functions?

Both are declared with the virtual keyword, but they are different. Virtual base classes ensure that only one instance is inherited by derived classes, whereas virtual functions have no implementation in the base class. They can be used together, to make sure only one instance is inherited but that each derived class can have its own implementation as well.

How are virtual base classes declared?

Virtual base classes are declared using the virtual keyword in the classes derived from the base class.

What is polymorphism?

Polymorphism is a concept that allows different object types to be treated as if of the same type. It’s often achieved by using virtual functions.

What is inheritance?

Inheritance is where a class takes on the properties of another class. The class that gives the properties is the parent or base class and the class which “inherits” the properties is the child or derived class.

This helps to form a relationship between classes and gives derived classes a way to modify the methods from the base class without affecting it directly. Along with virtual functions, inheritance helps to achieve polymorphic behavior.

What is encapsulation?

Encapsulation is a key principle of OOP languages, of hiding data and methods from external programs that don’t need access. This helps to organize code better, as well as avoid unnecessary modification of internal code.

What are the advantages of virtual base classes?

Virtual base classes avoid unnecessary duplication, help prevent the diamond problem, and generally make code simpler, more efficient, and less memory-intensive.

What are the limitations of virtual base classes?

Virtual base classes can potentially lead to very complex code, which affects performance, and are usually only applicable for specific situations, i.e. the diamond problem.

Since a strict hierarchy is introduced, this does reduce the flexibility available to the programmer, as any modifications to the base class have a compounding effect on the derived classes.

While code can be made more robust, it may be harder to understand, especially for programmers who didn’t create the classes.

To top