Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Multiple Inheritance: Using base class A's implementation for abstract method of base class B

I have an abstract class Interface that declares f() and g() methods.

MyClass implements Interface::g(), and MyClass inherits from Base, which implements its own f().

How can I make Base::f() be the implementation for Interface::f() in MyClass?

I don't want to make Base inherit from Interface directly, if possible.

class Interface {
    public:
        virtual void f() = 0;
        virtual void g() = 0;
};

class Base {
    public:
        void f() { }
};

class MyClass : public Interface, public Base {
    public:
        void g() { }
};

int main() {
    MyClass c;
    c.f();
    c.g();
}

This doesn't work, because f is still a pure virtual function in MyClass.

In Java, I would use the following approach, but it obviously doesn't work in C++.

public class MyClass extends Base implements Interface {
    public static void main(String argv[]) {
        MyClass c = new MyClass();
        c.f();
        c.g();
    }
    public void g() { }
}

class Base {
    public void f() { }
}

interface Interface {
    public void f();
    public void g();
}

The concrete problem I'm trying to tackle is the following:

The Interface in the example above is an abstract class Sender with different methods related to sending MIDI messages, e.g. update() (check if a message should be sent, and send it if necessary), and setAddress() to change the address of the message. The messages are MIDI events. I have to change the address/channel for functions like transposing and selecting different banks.

The Base class is a class Button. It has a method update() that checks whether the button is pressed or not, and calls the (virtual) methods press() and release() accordingly.

MyClass would then implement the press() and release() methods, to send the right data when the button state changes.

There are other types of Senders as well, and I keep them all in a list to update() them all at once, regardless of the specific type of Sender. I also need to be able to change the address of all Senders in the list (all at once).

The setAddress() method has nothing to do with a button, so it doesn't make sense to have Button inherit from Sender.
There are also other classes that would implement Button, but they are not all Senders.

Maybe I have to change the structure entirely, but I don't really see a better solution at the moment.

class Button {
    public:
        void update() {
            if ( /* check in hardware whether button is pressed */ )
                press();
        }
        virtual void press() = 0;
};

class Sender {
    public:
        virtual void update() = 0;
        virtual void setAddress(int address) = 0;
};

class ButtonSender : public Button, public Sender {
    public:
        void update() {
            Button::update();
        }
        void press() {
            /* send a message */
        }
        void setAddress(int address) {
            /* change the address */
        }
};

int main() {
    ButtonSender bs;
    Sender *s = &bs;
    s->update();
}
like image 273
tttapa Avatar asked Mar 21 '26 16:03

tttapa


2 Answers

To make this work you have to override f() in MyClass:

class MyClass : public Interface, public Base {
    public:
        void f() {
            Base::f();
        }
        void g() {
            cout << "MyClass::g()" << endl;
        }
};
like image 152
r3mus n0x Avatar answered Mar 23 '26 04:03

r3mus n0x


Why do you have a function called f in both Interface and Base when you subsequently derive from both of them in MyClass? You created a name clash right there, hence your difficulties. Ok, so you can get away with it this time with a three line method. But next time? And the next? No, don't go there.

C++ is not Java - it doesn't have interfaces. Instead, a concrete class (or chain of classes - using single inheritance) deriving from an abstract base class needs to implement all of the pure virtual methods declared by that class, as you have discovered.

What you are trying to do here goes against the spirit of the language and is likely to get you into trouble down the line so you need to adjust your thinking.

Multiple inheritance, especially when the same method or data member names are declared in one or more base classes, is usually a poor design choice and is symptomatic more often that not of errors inherent in the design of the class hierarchy in the first place so my recommendation is to revisit that - you'll be glad you did.

Anyway, now you know why you are were getting downvoted (although not by me). I hope you find this useful - it is well intended. I didn't have to write this but then again, I wanted to, I see this kind of thing a lot on SO and I find it painful.

like image 25
Paul Sanders Avatar answered Mar 23 '26 04:03

Paul Sanders



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!