📖
Go C++
  • Introduction
  • Chapter 1: What You Must Know First
    • Virtual Address Space of Process: Memory Partition and Layout
    • Function Call: Stack Frame
    • Program Compiling and Linking
  • Chapter 2: C++ Basics Improvement
    • Default Parameters
    • Inline Function
    • Function Overloading
    • new and delete
    • const and Pointers
    • References in Detail
  • Chapter 3: Object-Oriented Principles
  • Class and Object
  • Constructor and Destructor
  • Shallow Copy and Deep Copy
  • Initializer List
  • Various Member Functions
  • Pointer to Class Members
  • Chapter 4: Template Programming
  • Function Templates
  • Class Templates
  • Memory Allocators
  • Chapter 5: Operator Overloading
    • Operator Overloading
    • Introduction to Iterators
    • Issues of Iterator Invalidation
    • More about new and delete
    • Overloading of new and delete: Object Pool
  • Chapter 6: Inheritance and Polymorphism
    • Look inside Inheritance
    • More about Inheritance
    • Virtual Functions, Static Binding and Dynamic Binding
    • More about Virtual Functions
    • Understanding Polymorphism
    • Abstract Classes
    • Frequently Asked Interview Questions: Polymorphism
  • Chapter 7: Multiple Inheritance
    • Virtual Inheritance and Virtual Base Classes
    • Diamond Problem
    • Four Kinds of Type Conversions
  • Chapter 8: Standard Template Library
    • Sequence Containers
    • Container Adaptors
    • Associative Containers
    • More about Iterators
    • Function Objects
    • Generic Algorithms, Binders and Lambda Expressions
  • Chapter 9: Object Optimization
    • Behind the Object
    • Optimizing Objects in Functions
    • Member Functions with Rvalue References
    • Move Semantics and Perfect Forwarding
  • Chapter 10: Smart Pointers
    • Smart Pointers
    • Smart Pointers without Reference Counting
    • Smart Pointers with Reference Counting
    • Custom Deleters
  • Chapter 11: Function Objects and Binders
    • More about Binders
    • Introduction to std::function
    • Template Specialization and Argument Deduction
    • More about std::function
    • std::bind(): A Simple Thread Pool
    • More about Lambda Expressions
  • Chapter 12: Multithreading
    • Important Features in C++11
    • Multithreaded Programming with std::thread
    • Mutual Exclusion
    • Producer-Consumer Problem
    • Atomic Operations
    • Thread Visibility and volatile
  • Chapter 13: Design Patterns
    • Singleton Pattern
    • Factory Pattern
    • Proxy Pattern
    • Decorator Pattern
    • Adapter Pattern
    • Observer Pattern
Powered by GitBook
On this page

Was this helpful?

  1. Chapter 7: Multiple Inheritance

Virtual Inheritance and Virtual Base Classes

PreviousFrequently Asked Interview Questions: PolymorphismNextDiamond Problem

Last updated 5 years ago

Was this helpful?

Multiple inheritance means that a class can inherit from multiple base classes. Virtual Inheritance is a kind of inheritance that is widely used in multiple inheritance, by adding virtual before the access modifiers:

class A {
public:
private:
    int ma;
};
​
class B : virtual public A {
public:
private:
    int mb;
};

A class that is virtual inherited is a virtual base class. In this case, class A is a virtual base class. What is the difference between a virtual inheritance and a normal inheritance? The answer is the memory layout. In a normal inheritance, member variables of the base class locate at the front of the memory, and then goes the member variables of the derived class. But in a virtual inheritance, all the member variables of the base class is moved to end of the memory. What's more, the original location of these variables are replaced with a virtual base pointer (vbptr).

Just like vfptr, vbptr points to a virtual base table (vbtable). vbtable stores an upward offset which is 0 in this case, and the distance to the member variables of the base class. Here since A::ma moves to the end, the distance to its original location (where vbptr locates) is 8. Now class B needs an extra 4 bytes to store the vbptr, so its size is 12 bytes comparing to 8 in normal inheritance.

Now if class A has a virtual member function, and B virtually inherits from A:

class A {
public:
    virtual void func() {
        cout << "A::func()" << endl;
    }
private:
    int ma;
};
​
class B : virtual public A {
public:
    void func() {
        cout << "B::func()" << endl;
    }
private:
    int mb;
};

In the main function, we use an A pointer to point to a B object on the heap, then calls func() with the pointer. The program outputs normally, but you may have an error while deleting B. Why's that.

int main() {
    A *p = new B();
    p->func();  // B::func()
    delete p;   // ERROR
    return 0;
}

Notice that if we use a base pointer to point to a derived object, the pointer will always point at the start point of the base members. In this case, *p points at the vfptr of A. But since it is a virtual inheritance here, all members of A is moved to the end, and its original location is replaced with a vbptr. Now what happens when are deleting through *p?

It is kinda problematic and hard to figure out if you are using Visual Studio. But fortunately, g++ or clang++ have optimized accordingly and have no problem freeing the memory.

Another good reason not to use Windows for development.