using virtual inheritance to solve the diamond problem

how many instances of Base class are instantiated for one instance of secDerived which is derived from Derived class when you instantiate a secDerived demolist11_7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
using namespace std;

class Animal
{
public:
Animal()
{
cout << "animal constructor" << endl;
}
int age;
};

class Bird : public Animal
{
public:
Bird()
{
cout << "Bird constructor" << endl;
}
};

class Mammal : public Animal
{
public:
Mammal()
{
cout << "Mammal constructor" << endl;
}
};

class Reptile : public Animal
{
public:
Reptile()
{
cout << "reptile constructor" << endl;
}
};

class Platypus : public Mammal, public Bird, public Reptile
{
public:
Platypus()
{
cout << "platypus constructor" << endl;
}
};

int main()
{
Platypus duckBilled;
// duckBilled.age=10

return 0;
}

output

1
2
3
4
5
6
7
animal constructor
Mammal constructor
animal constructor
Bird constructor
animal constructor
reptile constructor
platypus constructor

As the output demonstrates, you have three instances of Animal created automatically for every single instance of a Platypus. This is ridiculous is still one animal. If uncommenting line 53, you get a compilation error simply because the compiler doesn't know whether you want to set Mammal::Animal::age or Bird::Animal::age or Reptile::Animal::age. It even more ridiculous, you could set all three:

1
2
3
duckBilled.Mammal::Animal::age = 10;
duckBilled.Bird::Animal::age = 10;
duckBilled.Reptile::Animal::age = 10

Obviously, one duckBilled should have only one age. We can solve this problem by using the keyword virtual

Syntax
1
2
3
4
5
6
7
8
class Derived2: public virtual Base
{
//...members and functions
};
class Derived2: public virtual Base
{
//...members and functions
};

improved code using virtual for demolist11_7

e.g. Demonstrating how virtual keyword in inheritance hierarchy helps restrict the number of instances of Base class to one. demolist11_8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
using namespace std;

class Animal
{
public:
Animal()
{
cout << "animal constructor" << endl;
}
int age;
};

class Bird : public virtual Animal
{
public:
Bird()
{
cout << "Bird constructor" << endl;
}
};

class Mammal : public virtual Animal
{
public:
Mammal()
{
cout << "Mammal constructor" << endl;
}
};

class Reptile : public virtual Animal
{
public:
Reptile()
{
cout << "reptile constructor" << endl;
}
};

class Platypus final : public Mammal, public Bird, public Reptile
{
public:
Platypus()
{
cout << "platypus constructor" << endl;
}
};

int main()
{
Platypus duckBilled;
duckBilled.age=10;

return 0;
}

output

1
2
3
4
5
animal constructor
Mammal constructor
Bird constructor
reptile constructor
platypus constructor

As the output demonstrates, the virtual keyword used in the relationship between classes Mammal Bird Reptile ensures that when these classes are grouped together under Platypus the common base Animal exits only in a single instance. Also note that line 41 the usage of keyword final to ensure that class platypus cannot be used as a base class.

the virtual keyword in c++ is used in different contexts for different purposes.

Summary:

  • a function declared virtual means that an exiting overriding function in a derived class invoked
  • an inheritance relationship declared using keyword virtual between classes Derived1 and Derived2 that inherits from class Base thats means that another class Derived3 which inherits from Derived1 and Derived2 still result in the creation of only one instance of Base during the instantiation of type Derived3.