Virtual base classes are used in virtual inheritance in a way of preventing multiple “instances” of a given class appearing in an inheritance hierarchy when using multiple inheritances.
Why we Need for Virtual Base Classes
Consider the situation where we have one class A . This class A is inherited by two other classes B and C. Both these class are inherited into another in a new class D as shown in figure below.
As we can see from the figure that data members/function of class A are inherited twice to class D. One through class B and second through class C. When any data / function member of class A is accessed by an object of class D, ambiguity arises as to which data/function member would be called? One inherited through B or the other inherited through C. This confuses compiler and it displays error.
#include <iostream>
using namespace std;
class A {
public:
int a;
A() // constructor
{
a = 10;
}
};
class B : public A {
};
class C : public A {
};
class D : public B, public C {
};
int main()
{
D object; // object creation of class d
cout << "a = " << object.a << endl;
return 0;
}
When we compile the above program, we will see the following error which is ambiguous of a member function.
g++ /tmp/9QQcpdLW2w.cpp /tmp/9QQcpdLW2w.cpp: In function 'int main()': /tmp/9QQcpdLW2w.cpp:26:34: error: request for member 'a' is ambiguous 26 | cout << "a = " << object.a << endl; | ^ /tmp/9QQcpdLW2w.cpp:6:13: note: candidates are: 'int A::a' 6 | int a; | ^ /tmp/9QQcpdLW2w.cpp:6:13: note: 'int A::a'
To resolve this ambiguity when class A is inherited in both class B and class C, it is declared as virtual base class by placing a keyword virtual
.
Virtual base classes offer a way to save space and avoid ambiguities in class hierarchies that use multiple inheritances. When a base class is specified as a virtual base, it can act as an indirect base more than once without duplication of its data members. A single copy of its data members is shared by all the base classes that use virtual base.
#include <iostream>
using namespace std;
class A {
public:
int a;
A() // constructor
{
a = 50;
}
};
class B : public virtual A {
};
class C : public virtual A {
};
class D : public B, public C {
};
int main()
{
D object; // object creation of class d
cout << "a = " << object.a << endl;
return 0;
}
Output
a =50