Open In App

Inheritance Ambiguity in C++

Last Updated : 21 Dec, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Pre-requisites: Inheritance in C++, Multiple Inheritance in C++

In multiple inheritances, when one class is derived from two or more base classes then there may be a possibility that the base classes have functions with the same name, and the derived class may not have functions with that name as those of its base classes. If the derived class object needs to access one of the similarly named member functions of the base classes then it results in ambiguity because the compiler gets confused about which base’s class member function should be called. 

Example:

C++




// C++ program to show inheritance ambiguity
 
#include<iostream>
using namespace std;
 
// Base class A
 
class A {
    public:
 
    void func() {
        cout << " I am in class A" << endl;
    }
};
 
// Base class B
 
class B {
    public:
 
    void func() {
        cout << " I am in class B" << endl;
    }
};
 
// Derived class C
 
class C: public A, public B {
 
 
};
 
// Driver Code
 
int main() {
 
    // Created an object of class C
 
    C obj;
 
    // Calling function func()
 
    obj.func();
   
    return 0;
}


Output:

prog.cpp: In function ‘int main()’:
prog.cpp:43:9: error: request for member ‘func’ is ambiguous
     obj.func();
         ^
prog.cpp:21:10: note: candidates are: void B::func()
     void func() {
          ^
prog.cpp:11:10: note:                 void A::func()
     void func() {
          ^

In this example, derived class C inherited the two base classes A and B having the same function name func(). When the object of class C is created and called the function func() then the compiler gets confused that which base class member function func() should be called.

Solution to  Ambiguity:

To solve this ambiguity scope resolution operator is used denoted by ‘ ::

Syntax:

ObjectName.ClassName::FunctionName();

Below is the program to show the concept of ambiguity resolution in multiple inheritances.

C++




// C++ program to resolve inheritance
// ambiguity
 
#include<iostream>
using namespace std;
 
// Base class A
 
class A {
    public:
 
    void func() {
        cout << " I am in class A" << endl;
    }
};
 
// Base class B
 
class B {
    public:
 
    void func() {
        cout << " I am in class B" << endl;
    }
};
 
// Derived class C
class C: public A, public B {
 
 
};
 
// Driver Code
 
int main() {
 
    // Created an object of class C
    C obj;
 
    // Calling function func() in class A
    obj.A::func();
 
    // Calling function func() in class B
    obj.B::func();
 
    return 0;
}


Output

 I am in class A
 I am in class B

Code Snippet:

  • We have created an “A” class which consists of the public member function “func”.
  • We have created a “B” class which also consists of the public member function “func”.
  • We have created a “C” class that is inheriting “A” and “B” classes.
  • Object “obj” is created of the derived class “C”.
  • The function “func” is called by the object “obj”.

The important thing to note here is that when the function “func” is called by the object “obj” first time it will invoke the function “func” of the “A” class and when the function “func” is called by the object “obj” second time it will invoke the function “func” of the “B” class because we had specified it using scope resolution operator “::” to get rid of ambiguity.

Function Overriding or Method Overriding

C++




// C++ program to show function/method overriding
 
#include<iostream>
using namespace std;
 
// Base class A
 
class A {
    public:
 
    void func() {
        cout << " I am in class A" << endl;
    }
};
 
// Base class B
class B {
    public:
 
    void func() {
        cout << " I am in class B" << endl;
    }
};
 
// Derived class C
class C: public A, public B {
    public:
   
    // Function overriding
    void func() {
        cout << " I am in class C" << endl;
    }
};
 
// Driver Code
 
int main() {
 
    // Created an object of class C
    C obj;
 
    // Calling function func() in class C
    // through scope resolution operator
    obj.C::func();
 
    // Calling function func() in class C
    // by default by compiler because of
    // method or function overriding
    obj.func();
 
    return 0;
}


Output

 I am in class C
 I am in class C

In this example, we can see that we have declared function func() in derived class “C” also. So, when an object of class “C” is created and called the function func(), then, “I am in class C” is printed because it will override the base class “func” method because of function/method overriding. Now, if we do not specify which class member function “func” has to be called through the scope resolution operator then by default the compiler runs the method which is written in the body of the class through which instance of the object is created. But if the function “func” was not present in the derived class “C” then for calling function “func” in class “A” or “B”, we have to specify it through the scope resolution operator. So, the compiler will run the method of the specified class.

Another Solution (using virtual inheritance)

In C++, you can use virtual inheritance to resolve ambiguity in inheritance. Virtual inheritance is a way of specifying that a class should be inherited virtually, meaning that only one instance of the class should be present in the inheritance hierarchy, even if the class is inherited multiple times.

Below is the program to show the concept of ambiguity resolution in multiple inheritances.

C++




#include <iostream>
using namespace std;
 
class A {
public:
    int x;
};
 
class B : virtual public A {
public:
    int y;
};
 
class C : virtual public A {
public:
    int z;
};
 
class D : public B, public C {
public:
    int w;
};
 
int main() {
    D obj;
    obj.x = 1;  // okay, no ambiguity
    obj.y = 2;  // okay, no ambiguity
    obj.z = 3;  // okay, no ambiguity
    obj.w = 4;  // okay, no ambiguity
    return 0;
}


In this example, class A is inherited virtually by classes B and C, so when class D inherits from both B and C, there is no ambiguity in the inheritance of A. As a result, you can access the members of A directly through an instance of D, without any issues.

Note that virtual inheritance can have some performance overhead, as it requires the use of additional pointers to manage the inheritance hierarchy. Therefore, it should only be used when necessary to resolve ambiguity in inheritance.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads