4

I understand virtual functions, but I am confused with virtual base classes and how it would work internally. Can someone please help?

class Base { };

Derived: virtual public Base { };

I do understand there is a single copy which is passed on to Derived classes.

  • But can someone please explain how this works internally?
  • How it will be similar or different to virtual functions ?
  • And how the call to base methods will get resolved?

  • What happens if the Derived class has virtual base class and a virtual function?

Thanks.

monish_koppa
  • 341
  • 2
  • 8
  • As long as it behaves as specified by the C++ standard, why do you care? – Jesper Juhl Nov 22 '19 at 19:02
  • its not a dup for the link specified. My question is more specific to virtual base class and how it is different from virtual functions, internally. @NathanOliver-ReinstateMonica – monish_koppa Nov 22 '19 at 19:03
  • The internal details for how virtual base classes are implemented is not specified and is a compiler detail. (As is how virtual functions are implemented.) – 1201ProgramAlarm Nov 22 '19 at 19:34
  • Usually, it involves an additional pointer (like the vtable pointer) that points to some metadata, including an offset, which will tell where is the virtual base body from the current `this`. Once the base body is found, it behaves as usual, you can find the vtable pointer etc... I don't really know the details enough to write an answer though. – ElderBug Nov 22 '19 at 19:47
  • Does this answer your question? [Why does virtual inheritance need a vtable even if no virtual functions are involved?](https://stackoverflow.com/questions/57482925/why-does-virtual-inheritance-need-a-vtable-even-if-no-virtual-functions-are-invo) – Davis Herring Nov 22 '19 at 23:04
  • @DavisHerring no, this does not. I want to know how is virtual base classes internally implemented. I have gone through most of the links on stack overflow, before posting the question. I could not find any concrete and direct answer to this question. – monish_koppa Nov 23 '19 at 06:46
  • This question has been bugging me for sometime and I have also faced this question in couple of interviews, about the implementation details of virtual base classes. – monish_koppa Nov 23 '19 at 06:49
  • @helloworld134: But it does talk about the implementation in terms of a virtual table that contains layout information about the complete object (which thereby ends up containing several virtual pointers in general, even with only one virtual base). How does that *not* answer this question? – Davis Herring Nov 23 '19 at 17:11
  • If you really want to know, get Lippman's [Inside the C++ Object Model](https://www.amazon.com/Inside-Object-Model-Stanley-Lippman/dp/0201834545). You can find a free PDF online (I'm not linking to it as I'm not sure it's published with the permission of the author). – Igor Tandetnik Nov 23 '19 at 23:30

1 Answers1

0

Virtual base classes have been introduced to eliminate something called diamond problem occurred in multiple inheritance in C++. For instance,

 #include <iostream>
#include <string>

using namespace std;

class Dog{
    string color;
public:
    Dog(string color): color(color)
    {cout<<color<<" Dog created"<<endl;}
};

class Rotweiler: public Dog{
    int age;
public:
    Rotweiler(int age, string color): Dog(color), age(age)
    {cout<<"Age "<<age<<" "<<color<<" Rotweiler created"<<endl;}
};

class Husky: public Dog{
    int teeth;
public:
    Husky(int teeth, string color): Dog(color), teeth (teeth)
    {cout<<"Teeth "<<teeth<<" "<<color<<" Husky created"<<endl;}
};

class MixBreed: public Rotweiler, public Husky{
public:
    MixBreed(int teeth, int age, string color): Rotweiler(age,color), Husky(teeth,color)
    {cout<<"Teeth "<<teeth<<" Age "<<age<<" "<<color <<" MixBreed created"<<endl;}
};

int main(){
    MixBreed puppy(24,4,"black");
}

This code will result in,

black Dog created
Age 4 black Rotweiler created
black Dog created
Teeth 24 black Husky created
Teeth 24 Age 4 black MixBreed created

As you can see, we intended to create one Dog and Two others Rottweiler and Husky derived from the same Dog and finally a MixBreed derived from Rottweiler and Husky. But the compiler created two separate Dog base class objects rather deriving from the same Dog object. To address this issue, we can use the virtual inheritance.

  #include <iostream>
#include <string>

using namespace std;

class Dog{
    string color;
public:
    Dog(string color): color(color)
    {cout<<color<<" Dog created"<<endl;}
};

class Rotweiler: virtual public Dog{
    int age;
public:
    Rotweiler(int age, string color): Dog(color), age(age)
    {cout<<"Age "<<age<<" "<<color<<" Rotweiler created"<<endl;}
};

class Husky: virtual public Dog{
    int teeth;
public:
    Husky(int teeth, string color): Dog(color), teeth (teeth)
    {cout<<"Teeth "<<teeth<<" "<<color<<" Husky created"<<endl;}
};

class MixBreed: public Rotweiler, public Husky{
public:
    MixBreed(int teeth, int age, string color): Dog(color), Rotweiler(age,color), Husky(teeth,color) // notice Dog constructor called here
    {cout<<"Teeth "<<teeth<<" Age "<<age<<" "<<color <<" MixBreed created"<<endl;}
};

int main(){
    MixBreed puppy(24,4,"black");
}

Notice now Rottweiler and Husky virtually inherit the class Dog. Our ultimate goal is to avoid creation of duplicate base classes. This code will result,

black Dog created
Age 4 black Rotweiler created
Teeth 24 black Husky created
Teeth 24 Age 4 black MixBreed created

But another thing to notice here is that Dog object has been created by the most derived class which is class MixBreed (you can see the Dog() constructor is called). This is because both Rotweiler and Husky are virtually inheriting Dog. When the above code compiles, the most derived class which is MixBreed should call the Dog constructor to create the one and only Dog object or else an error will result. Both Dog constructor calls from Rotweiler and Husky are ignored since Dog object has already created from the MixBreed class.

  • Virtual base class objects are created at the very beginning by the compiler to avoid duplication.
  • The most derived class is now responsible for creating the virtual base class object
  • If you instantiate Rotweiler or Husky, they will work as normal (they will create Dog objects)

Another fact to remember is all all classes inheriting a virtual base class will have a virtual table, and they will point to the same base class object by a pointer. Therefore all derived classes from the base class can access the behaviors of the base class.