About multiple inheritance and defining virtual function
Asked Answered
A

3

13

I have a multiple inheritance scenario without virtual base classes like this:

 Ta  Tb
 |   |
 B   C
  \ /
   A

Ta and Tb are two different template classes that both declare a virtual function named f(). I want to override the two function in the A scope, because I have to interact with both B and C data in these methods. But I don't know how to do this.

class Tb {
protected:
    virtual void f() {};
public:
    void call() {
        this->f();
    };  
};

class Tc {
protected:
    virtual void f() {};
public:
    void call() {
        this->f();
    };
};

class B : public Tb {
public:
    void doSomething() {};
};

class C : public Tc {
private:
    int c;
public:
    void inc() { c++; };
};

class A : public B, public C {
protected:
    void f() { // this is legal but I don't want to override both with the same definition.
        // code here
    }
    // if Tb::f() is called then i want to call C::inc()
    // if Tc::f() is called then i want to call B::doSomething()
public:
    void call() {
        B::call();
        C::call();
    };
};

Is there a syntax to override both the methods with different definitions or do I have to define these in B and C?

Thanks

Edit: My problem is not that a cant call Tb::f() or Tc::f(), but that i want to define two different behavior if Tb::f() or Tc::f() is called. These methods are called by Tb and Tc itself in its own public methods. Modified the example so maybe is more clear what i want to do...

Algae answered 6/5, 2011 at 12:51 Comment(0)
O
7

Is there a syntax to override both the methods with different definitions or do I have to define these in B and C?

Short answer: no.

Your A:f() will override both Ta::f() and Tb::f().

If you want different overrides, the only solution is to insert helper classes Hb and Hc:

Ta  Tb
|   |
B   C
|   |
Hb  Hc
 \ /
  A 

Hb can be as small as two functions, just to rename the function:

class Hb: public B {
   protected: // overrides from Ta
     virtual void f() { Ta_f(); }

   protected: // new virtuals
     virtual void Ta_f() = 0;
 };

and then you can define A::Ta_f() to do whatever you want (including calling B::f() ! )

Outwards answered 6/5, 2011 at 13:35 Comment(4)
Thanks for the advice, i had in mind that solution, but because it add a layer i was remissive of using it and searching for another solution. But there aren't so i'm using it.Algae
@Gianni Technically, there is no obstacle to do what you want. There just is no syntax in C++ to do it. (E.g. C# has a syntax to do exactly what you wanted)Outwards
C# doesn't have multiple inheritance at all.Expropriate
@Vlad C# has multiple inheritance, but it is restricted to interfaces only. As a result, the programmer does not need to know about it. Still, behind the scenes the compiler has to solve most of the problems that arise from implementing multiple inheritance (e.g. trampoline functions that adjust the this/self pointer).Outwards
E
3

You did override both in class A. If you didn't, there would have been an ambiguity unless using directive is used to explicitly specify what method of those you prefer.

You can override those methods separately in B and C classes, but again, once A class inherits both you have to decide which one should be used.

Expropriate answered 6/5, 2011 at 12:57 Comment(3)
couldn't you dispatch from withing A::f, calling b::f() or c::f() ?Fissionable
This does not really answer the question (how to override the methods differently), does it?Undermine
@Mario: You could. But easier is to say using b::f and not write a dummy implementation that calls one of the base class's method.Expropriate
E
3

Do you absolutely have to be able to substitute an A for either a Tb or a Tc? If not, have you considered using composition in A instead of inheritance?

If you need to substitute in such a way, have you considered taking the easy way and just calling the parent methods two different names? Since you want to override them separately the indication is that they aren't doing the same thing.

Essayist answered 6/5, 2011 at 13:28 Comment(1)
Excellent point. It's generally useful when your class design obeys the Liskov substitution principle.Expend

© 2022 - 2024 — McMap. All rights reserved.