Virtual Inheritance
By: Chuan Zhang
Tags: Oops Concepts, Cpp

Nov. 23. 2015

In this post, after introducing two preliminary concepts, I explain what virtual inheritance is, and how it is implemented, then introduce two applications of virtual inheritance. One involves multiple inheritance, and the other involves implementation of non-inheritability. For each case, one example demonstrating how virtual inheritance works is presented.

Some Preliminaries

Before discussing virtual inheritance, it is necessary to explain two very important concepts in OOP (Object Oriented Programming) concepts, static and dynamic binding.

Roughly speaking, static binding occurs at compile time, and dynamic binding occurs at run time. In C++, the two kinds of polymorphism (see Appendix for Classification of Polymorphism), overloading and overriding are two typical examples of these two concepts. For function overloading, when an overloaded function is called, during compile time, the compiler determines which version is actually called by matching their parameter type patterns. Whereas, for function overriding, C++ implements virtual function call resolution with a vtable data structure [4]. In C++, virtual inheritance is also implemented with vtable. Next, we explain what virtual inheritance is, and how it is implemented.

What is “virtual inheritance”? why we need it?

According to Wikipedia [1], “virtual inheritance is a technique used in C++, where a particular base class in an inheritance hierarchy is declared to share its member data instances with any other inclusions of that same base in further derived classes.”

It is well-known that, different from other OOP languages such as Java and C#, C++ supports multiple inheritance, which is complicated, and its necessity is controversial [2]. Virtual inheritance may be required when multiple inheritance is used. For example, diamond problem, which may cause name ambiguity, needs virtual inheritance to be solved when some member function(s) of the common base class is(are) not pure virtual. Next, we explain how virtual inheritance is implemented in C++.

vtable — How “virtual inheritance” is implemented?

Just similar to function overriding, C++ implement virtual inheritance with a vtable data structure. However, it is necessary to notice that different compilers may implement virtual inheritance with vtable in different ways.

For g++ compiler, both virtual functions and virtual base classes share one single vtable. Every instance of a class with virtual inheritance begins with a virtual pointer to the corresponding class.

For MSVC compiler, virtual functions and virtual base classes are stored in separate vtables, and the table for virtual functions is named as vftbl, and the table for virtual base classes is called vbtbl.

“Diamond Problem” and Virtual Inheritance

“Diamond Problem”

class Employee

{

public:

int e_id;

string e_name;

virtual int eSalary() const;

}; class Manager: public Employee

{

public:

int eSalary() const;

}; class Contractor: public Employee

{

public:

int eSalary() const;

}; class TempManager: public Manager, public Contractor

{

public:

int eSalary() const;

};

Appendix: Classification of Polymorphism

Following Cardelli and Wegner [3], Polymorphism can be classified into two categories and four different kinds:

Ad-hoc Polymorphism (a.k.a non-universal polymorphism): ad-hoc polymorphic functions work on a finite set of different and potentially unrelated types. There are two kinds of ad-hoc polymorphism: overloading and coercion.

Overloading: the same name is used to denote different functions, and the context is used to decide which function is denoted by a particular instance of the name. In C++, overloading occurs in the same class, and at compile time (this is why it is called static binding or early binding). Coercion (a.k.a casting): a coercion is a semantic operation which is needed to convert an argument to the type expected by a function. Coercions can be provided statically, by automatically inserting them between arguments and functions at compile time, or may have to be determined dynamically by run-time tests on the arguments.

Universal Polymorphism: universally polymorphic functions work on an infinite number of types with a given common structure. There are two kinds of universal polymorphism: parametric and subtyping.

Parametric: a polymorphic function has an implicit or explicit type parameter, which determines the type of the argument for each application of that function. This kind of polymorphism lets us to define codes that are generic: they can be instantiated to handle different types, and the functions that exhibit parametric polymorphism are also called generic functions. In C++, this kind of polymorphism is implemented with templates. Subtyping (a.k.a Inclusion Polymorphism, Dynamic Polymorphism or Runtime Polymorphism): an object can be viewed as belonging to many different classes which need not be disjoint, i.e. there may be inclusion of classes. In this polymorphism, elements of a subrange type also belong to superrange types, and this is the well-known Liskov’s Substitution Principle, which says that in any situation in which the left-hand-side of an assignment expects a type T, it can also receive a type S, as long as S is subtype of T. In C++, if we have a class D inherits from another class B, then any function accepting an argument of type B (either variable of type B, or reference or pointer to B) will also accept an argument of type D (variable of type D, or reference or pointer to D).

References

[1]. Wikipedia: Virtual Inheritance

[2]. Marc Gregoire, Nicholas A. Solter & Scott J. Kleper (2011) Professional C++. 2nd edition, John Wiley & Sons, Inc., Indianapolis, Indiana. </p>

[3]. Cardelli, L. & Wegner, P. (1985) On Understanding Types, Data Abstraction, and Polymorphism. Computing Surveys Vol. 17(4), pp 471–522

Webber, A (2010) Moder Programming Languages: A Practical Introduction. Franklin, Beedle & Associates Inc.

WikiBooks: (2014) Introcution to Programming Languages

[4]. WikiPedia: Virtual Method Table (vtable)