Multiple inheritance. Duplicate class and its data. Rhombus problem
Contents
- 1. Case of ambiguity in a class under multiple inheritance
- 2. Avoid code duplication and ambiguity. Declaring class A as virtual
- 3. Sample code that results in call ambiguity
- 4. The sample code solves the problem of ambiguous calling and duplication of class data. Declaring the class as virtual
- Related topics
Search other websites:
1. Case of ambiguity in a class under multiple inheritance
Ambiguity in multiple inheritance can arise in cases where the reference to an element of the base class can be interpreted differently (two or more ways). In this case, the compiler issues an appropriate message.
For example, Figure 1 shows a code snippet and a corresponding class hierarchy that leads to ambiguity and data duplication.
Figure 1. A class hierarchy in which the inversion of class A elements can cause ambiguous interpretation, as well as duplication of class data
Using the code in Figure 1, the data of class A is duplicated, that is, it is used twice. Also accessing a protected variable with the name value of class A, for example,
value
Will cause a compilation error: ambiguous call.
To fix this error, you need to clearly indicate which class is being called through. That is, specify the following line in the D::GetValue() function
return B::value;
or
return C::value;
⇑
2. Avoid code duplication and ambiguity. Declaring class A as virtual
To avoid duplication of code and data of class A (see Figure 1), you need to declare class A as virtual in classes B, C:
class B : public virtual A // the virtual keyword makes a single copy of class A { ... } ... class C : virtual public A // the virtual keyword makes a single copy of class A { ... }
Then the class hierarchy described in Figure 1 may have a different form, as shown in Figure 2
Figure 2. Class hierarchy, if class A is inherited in classes B and C as virtual.
The problem of ambiguity is also solved. Now in class D you can safely refer to the name
A::value
or
value
There will be no more error.
⇑
3. Sample code that results in call ambiguity
The example shows the code of the program that implements the class hierarchy shown in Figure 1. In class D, in the Show() method, an attempt to access the name a will cause an ambiguous call error. To fix the situation, you need to explicitly specify the base classes.
B::a
or
C::a
Also in this case, there is a duplication of code and data of class A.
#include <iostream> using namespace std; // The problem of class duplication in multiple inheritance class A { protected: int a; public: A(int a) : a(a) { } void Show() { } }; class B : public A { protected: int b; public: B(int a, int b) : A(a), b(b) { } }; class C : public A { protected: int c; public: C(int a, int c) : A(a), c(c) { } }; class D : public B, public C { public: D(int a, int b, int c) : B(a, b), C(a, c) { } void Show() { // there is an error, ambiguous call a // cout << a << endl; - you need to explicitly specify the class cout << B::a << endl; // works here because class B is specified explicitly cout << C::a << endl; // works here because class C is specified explicitly } }; int main() { D obj(1, 2, 3); obj.Show(); }
4. The sample code solves the problem of ambiguous calling and duplication of class data. Declaring the class as virtual
The example demonstrates a program that implements the program code shown in Figure 2.
// In this code, class A is inherited as virtual. // The problem of ambiguity in the class D is no longer there. class A { public: int value; public: A(int value) : value(value) { } A() : value(0) { } }; class B : public virtual A // the virtual keyword makes a single copy of class A { public: B(int value) : A(value) { } }; class C : virtual public A // virtual keyword produces one copy of class A { public: C(int value) : A(value) { } }; class D : public B, public C { public: // There is no ambiguity here, since class A code is not duplicated (thanks to virtual inheritance) int Value() { return value; } D(int value) : A(value), B(value), C(value) { } D() : B(0), C(0) { } }; void main() { A objA(5); D objD(10); cout << objD.Value() << endl; }
⇑
Related topics
- Inheritance. General concepts. Using private, protected, public modifiers when inheriting
- Order of calling constructors during inheritance. Inheritance restrictions. Properties to the pointer to the base class
⇑