Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use multiple inheritance to satisfy abstract base class

Why exactly doesn't this work? Are the inherited function signatures subtly incorrect or is the abstract base class enforced "before" the member functions are inherited or is it something else? Could this be convinced to work without function wrappers?

#include <iostream>

struct AbsBase {
    virtual void foo() = 0;
    virtual void bar() = 0;
};

struct ProvideFoo {
    void foo() { std::cout << "foo\n"; }
};

struct ProvideBar {
    void bar() { std::cout << "bar\n"; }
};

struct Concrete : public ProvideFoo, public ProvideBar, public AbsBase {
    // I guess I could put function wrappers here... sigh...
    //void bar() {ProvideBar::bar();}
    //void foo() {ProvideFoo::foo();}
};

int main() {
    Concrete c;
    c.foo();
    c.bar();
}
like image 253
Praxeolitic Avatar asked Sep 08 '25 01:09

Praxeolitic


1 Answers

Why your code fails to compile

I think the downvoters are a bit harsh on you, as your reasoning to supply the implementations of the two pure virtual functions through separate classes has some intuitive appeal.

Alas, you are doing two unrelated things at the same time. ProvideFoo and ProvideBar are completly unrelated to the AbsBase abstract class. You could also subclass both of them from AbsBase, but then each of them would still be an abstract class. In either case, your current Concrete is an abstract class because it derives from at least one class with a pure virtual function. You can't create objects from such classes.

Fixing your code, part I

The easiest way is to drop subclassing from AbsBase altogether and subclass from ProvideFoo and ProvideBar directly. Of course, now you don't have virtual functions inside Concrete, so further subclassing can't easily override foo and bar functionality.

#include <iostream>

struct ProvideFoo {
    void foo() { std::cout << "foo\n"; }
};

struct ProvideBar {
    void bar() { std::cout << "bar\n"; }
};

struct Concrete : public ProvideFoo, public ProvideBar {};

int main() {
    Concrete c;
    c.foo();
    c.bar();
}

Live Example I

Fixing your code, part II

You can also create multiple interfaces and multiple concrete implementations, something like this:

#include <iostream>

struct AbsFoo {
    virtual void foo() = 0;
};

struct AbsBar {
    virtual void bar() = 0;
};

struct ProvideFoo: AbsFoo {
    void foo() { std::cout << "foo\n"; }
};

struct ProvideBar: AbsBar {
    void bar() { std::cout << "bar\n"; }
};

struct Concrete : public ProvideFoo, public ProvideBar {};

int main() {
    Concrete c;
    c.foo();
    c.bar();
}

Live Example II

Fixing your code, part III

Now for the encore: you can also use virtual inheritance when subclassing ProvideFoo and ProvideBar from AbsBase by using the virtual keyword

#include <iostream>

struct AbsBase {
    virtual void foo() = 0;
    virtual void bar() = 0;
};

struct ProvideFoo: virtual AbsBase {
    void foo() { std::cout << "foo\n"; }
};

struct ProvideBar: virtual AbsBase {
    void bar() { std::cout << "bar\n"; }
};

struct Concrete : public ProvideFoo, public ProvideBar {};

int main() {
    Concrete c;
    c.foo();
    c.bar();
}

This is really advanced C++ and can become really complicated if your classes also contain member data. I would prefer to use the 2nd solution for your code.

Live Example III

like image 173
TemplateRex Avatar answered Sep 10 '25 00:09

TemplateRex