0

I have a problem with multiple inheritance and it would be great if someone could help me out. I am programming a situation which ultimately boils down to something similar to this

    class A {
public:
    A(){}
    virtual ~A() = 0;
    virtual void print()=0;
};
A::~A(){}

class B: public virtual A {
public:
    B():A(){}
    virtual ~B() = 0;
    virtual void print() {
        cout << "Hello" << endl;
    }
};
B::~B(){}

class C: public virtual A {
public:
    C():A(){}
    virtual ~C() = 0;
    virtual void print () {
        cout << "Bye" << endl;
    }
};
C::~C(){}

class D: public B, public C {
public:
    D():B(),C(){}
    virtual ~D(){}
    virtual void print(){}
};

int main()
{
    D d;
    A* a = &d;
    a->B::print(); //The statement leads to errors
    a->C::print(); //The statement leads to errors
}

I need to access the the implementation of the virtual function in class B and class C. Is there a way to do this?

5
  • 2
    cast the pointer? Commented Jan 8, 2018 at 16:55
  • D* a = &d; fixes that. Commented Jan 8, 2018 at 16:56
  • Could you give the B version an alias or alternate name you can call? Commented Jan 8, 2018 at 16:56
  • Possible duplicate of C++ base class function call from last derived in diamond design Commented Jan 8, 2018 at 16:57
  • Hi @maxim, actually the inheritance chain is quite big and A actually inherits from a bunch of other classes. I wanted to actually dynamically dispatch the execution of the execution of the print() from the upper classes and not have a pointer to D which kills the dispatching Commented Jan 8, 2018 at 17:28

4 Answers 4

1

Type A does not know about implementations in subclasess B and C at all. To call these members, you'll first have to cast a to at lease B or C, or even to D:

D* aAsD = dynamic_cast<D*>(a);
if (aAsD) {
    aAsD->B::print(); 
    aAsD->C::print();
}
Sign up to request clarification or add additional context in comments.

3 Comments

Hi, dynamic_cast is not unfortunately an attractive solution in my case because I am targeting embedded systems
However, static_cast might still be allowed
@RaghurajTarikere • back when I did some embedded programming using C++, there were certain features of C++ that we weren't allowed to use (disabled by compiler switches). We couldn't use RTTI, exceptions, virtual polymorphism, or streams. To build sort-of-kind-of the structure you have, we'd use containment and member functions that would forward dispatch (thunk) to the correct member object. Sounds like you can use all of C++, but the technique may be helpful for you to consider.
0

To understand this, ignore the inheritance for a second:

  1. Class 'A' doesn't has a print method
  2. Class 'B' and 'C' have their own printing methods
  3. Class 'D' has no printing methods by itself.

Now add the inheritance to the equation:

  1. Class 'D' inherits 'B' and 'C', so it has both printing methods
  2. Class 'B' and 'C' inherits 'A', but as 'A' has no printing methods, they still have the same methods
  3. Class 'A' has no printing methods.

When you cast A* a = &d, you are transforming a class with two printing methods to a class without printing methods. Thanks to the power of inheritance, the 'A' class printing method is now overloaded by the one in 'D' class, but 'a' variable is still an 'A' class (with overloads from 'D'). As 'A' doesn't inherits 'B' or 'C', it doesn't knows what they are. Reason why you are getting the error when trying to use them.

A solution to this would be simply not casting 'D' to 'A':

int main() {
    D d;
    d.B::print(); //Hello
    d.C::print(); //Bye
}

Also, if you need to cast 'D' to 'A', you should upcast it to B or C accordingly:

int main() {
    D d;
    A* a = &d;
    dynamic_cast<B*>(a)->B::print();
    dynamic_cast<C*>(a)->C::print();
}

Or a 1 dynamic cast version:

int main() {
    D d;
    A* a = &d;
    D* dptr = dynamic_cast<D*>(a);
    dptr->B::print();
    dptr->C::print();
}

In other words, you must upcast 'a' to something that inherits 'C' and 'B' before using 'C' and 'B' respectively

2 Comments

reinterpret casting (better than dynamic casting for embedded systems) the A pointer to B or C and then calling the functions on them works good for me. But it still makes the final code non-portable which is of some concern
Without casting the pointer, there's no way on accessing 'B' or 'C' printing methods. You can, tough, access all 'D' methods. Can't you just create a method in D which prints 'B' or 'C' accordingly? Maybe with an enum as an argument
0

A *a has no idea about print() inside B or C.You might want D to handle whether to call B::print() or C::print().

class D: public B, public C {
public:
    D():B(),C(){}
    virtual ~D(){}
    virtual void print()
    {
       B::print(); //or some logic to call one of them
       C::print();
    }    
};

and

D d;
A* a = &d;
a->print(); 

Comments

0

There's something that seems wrong about the entire desire to do B::Print or C::print like that ... especially as you're making it a no-op in D.

it suggests that maybe D shouldn't inherit B and C, but contain a B and a C. Then you can expose B and C separately from D which can be passed around as A's individually.

Obviously this might not work for your expanded problem, but for the one you've posted; I would call this inheritance abuse.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.