I'm trying to design a class hierarchy in C++ where I have a base interface FooInterface
with a pure virtual function foo()
, and another interface FooBarInterface
that should extend FooInterface
and add an additional function bar()
. I then have a class Foo
that implements foo()
from FooInterface
, and a class FooBar
that inherits from Foo
and FooBarInterface
and implements bar()
.
My goal is to have the func
function accept a std::shared_ptr
to any object that implements both foo()
and bar()
.
#include <memory>
class FooInterface {
public:
virtual void foo() = 0;
};
class FooBarInterface : public FooInterface {
public:
virtual void bar() = 0;
};
class Foo : public FooInterface {
public:
void foo() override {};
};
class FooBar : public Foo, public FooBarInterface {
public:
void bar() override {};
};
void func(std::shared_ptr<FooBarInterface> fb) {}
int main() {
func(std::make_shared<FooBar>());
}
Note: omitting virtual destructor.
However, this code does not compile probably because that foo()
in FooBarInterface
is not overridden in FooBar
, even though FooBar
inherits from Foo
, which implements foo()
.
How should I modify my code? Or do you have any design pattern that I should refer to?
I got lost in the Foo
s and the Bar
s and the Interfaces
, so I'm going to rewrite the class hierarchy, keeping the same structure:
struct Base {
virtual void foo() = 0;
}
struct Intermediate1 : Base {
};
struct Intermediate2 : Base {
void foo();
}
struct Derived : Intermediate1, Intermediate2 {
};
Derived d; // error: can't create object of an abstract type
An object of the Derived
has two subobjects of type Base
, one coming through Intermediate1
and the other coming through Intermediate2
. So it has two different functions foo
, one coming through Intermediate1
and one coming through Intermediate2
. Since Intermediate1
does not override Base::foo
(and Derived
also doesn't override it), it's still a pure virtual function, so Derived
is an abstract class and cannot be instantiated.
On the other hand (and how many folks picture inheritance of "interfaces" (quoted because C++ doesn't have a formal notion of an "interface")), a similar hierarchy could look like this:
struct Base {
virtual void foo() = 0;
}
struct Intermediate1 : virtual Base {
};
struct Intermediate2 : virtual Base {
void foo();
}
struct Derived : Intermediate1, Intermediate2 {
};
Derived d; // okay, via "dominance"
Note the added virtual
for the classes derived directly from Base
. Now an object of type Derived
has only one subobject of type Base
, and the dominance rule says that in Derived
, Intermediate2::foo
overrides Base::foo
, even though there is no override in Intermediate1
. So Intermediate1
itself is an abstract class, but Derived
is not, even though it doesn't override Base::foo
; the override through Intermediate2
is sufficient.