-1

I know this was asked many times but I could not found a suitable solution for my problem.

I have something like the following code:

#include <iostream>
#include "stdafx.h"

using namespace std;

class A                              //can not modify
{
public:
    double ComputeValue(double val)
    {
        return val + 1;
    }
};
class B : public A {};               //can not modify
class C : public A {};
class D : public B, public C {};
class E                              //can not modify
{
public:
    double GetValue(A *a)
    {
        double x = 4;
        return a->ComputeValue(x);
    }
    double DoSomething()
    {
        return GetValue(new D());
    }
};

int main()
{
    E *e = new E();
    cout << e->DoSomething();
    return 0;
}

I get the Error ambiguous conversion from 'D * to A *' in DoSomething. I know that I could solve this problem using "diamond inheritance". But I could not change class A or class B or class E because they already been used in a lot of location and a change like it is described in the diamond inheritance could produce problems in the application. So i can modify just class C or class D.

To clarify what I need to do is to make a new class inherited from A: C and to make class D inherit this new class without causing problems in F. I am looking in a method to block in class D the inheritance of A from C. Also to make class B inheriting from C or to modify B to do everything C is doing is not an option.

student
  • 352
  • 2
  • 15

2 Answers2

1

This is the diamond inheritance problem, you need to inherit from A virtually.

class B: virtual public A{}
class C: virtual public A{}

For more see How does virtual inheritance solve the "diamond" (multiple inheritance) ambiguity? and https://isocpp.org/wiki/faq/multiple-inheritance#mi-diamond

Curious
  • 20,870
  • 8
  • 61
  • 146
  • @student what do you mean? You cannot change the code you are working on? – Curious Jul 03 '17 at 06:01
  • Due to extensive use of the A, B, E and F it is possible to have multiple problems like for example the one described here : https://stackoverflow.com/a/25689818/4621626 . The application is to developed to risk it :( – student Jul 03 '17 at 06:06
1

Since you have all the modifications restrictions, you can solve the ambiguity by static casting the D pointer to any of the base classes, C or B. This way, the compiler will know which instance of A you are referring (which will be the base class of the casted type):

class F
{
    public:
    bool DoSomething()
    {
        double s;
        E *e = new E();
        D *d = new D();
        s = e->GetValue(static_cast<C*>(d));
    }
}

But this solution is 99% of the times wrong. In D you will have two different copies of A (as others have commented, because of the diamond problem), so calling GetValue using the casting solution will return one of the two GetValues that D class can have, leading to possible problems.


Another solution would be changing Dclass. Instead of using inheritance, use composition:

class D{
public:
    D():
        b_ptr(new B),
        c_ptr(new C),
        a_ptr(b_ptr) //Or c_ptr, the one you want.
    {
    }
    double ComputeValue(double val)
    {
      //Use a_ptr, which you have already initialized from constructor
    }

    A* a() {return a_ptr;}
    B* b() {return b_ptr;}
    C* c() {return c_ptr;}
private:
    B *b_ptr;    
    C *c_ptr;    
    A *a_ptr;    //Initialized from any of the above.
}

But again, the perfect solution would be resolving the diamond problem, but for that you have to change B or C classes. These are only workarounds, that will probably lead in a future to harder problems.

LoPiTaL
  • 2,495
  • 16
  • 23