Is it possible to have a number of partial implementations of an abstract interface, and then collect these partial implementations into a single concrete class by using multiple inheritence?
I have the following example code:
#include <iostream>
struct Base
{
virtual void F1() = 0;
virtual void F2() = 0;
};
struct D1 : Base
{
void F1() override { std::cout << __func__ << std::endl; }
};
struct D2 : Base
{
void F2() override { std::cout << __func__ << std::endl; }
};
// collection of the two partial implementations to form the concrete implementation
struct Deriv : D1, D2
{
using D1::F1; // I added these using clauses when it first didn't compile - they don't help
using D2::F2;
};
int main()
{
Deriv d;
return 0;
}
This fails to compile with the following errors:
main.cpp: In function ‘int main()’:
main.cpp:27:11: error: cannot declare variable ‘d’ to be of abstract type ‘Deriv’
main.cpp:19:8: note: because the following virtual functions are pure within ‘Deriv’:
main.cpp:5:18: note: virtual void Base::F1()
main.cpp:6:18: note: virtual void Base::F2()
Try inheriting virtually from
Base
:Without the virtual inheritance, your multiple inheritance scenario looks like inheritance from two separate and incomplete base classes
D1
andD2
, neither of which can be instantiated.Yes.
Each
Base
base class subobject brings two pure virtual functions. How many of those base subobjects do you want inDeriv
?Base
base class subobject,Deriv::D1::Base
andDeriv::D2::Base
(so conversions fromDeriv&
toBase&
would be ambiguous) then you will have 4 different virtual functions inDeriv
:Deriv::D1::Base::F1()
,Deriv::D1::Base::F2()
,Deriv::D2::Base::F1()
,Deriv::D2::Base::F2()
. Only the first and last ones are implemented, so the two middle ones are pure virtual:Deriv::D1::Base::F2()
,Deriv::D2::Base::F1()
. You have two entirely independent inheritance relations:Deriv
inherits fromD1
andDeriv
inherits fromD2
.Base
base class subobjectDeriv::Base
, then you will have only 2 different virtual functions inDeriv
:Base::F1()
,Base::F2()
.Non-virtual inheritance in C++ is "concrete" inheritance, like containment:
struct D : B
means that for eachD
object there is exactly oneB
base class subobject, just likestruct C { M m; }
means that for eachC
there is exactly oneM
class member subobject. These relations are one-to-one.OTOH, virtual inheritance is a more "abstract":
struct D : virtual B
means that for eachD
object is associated with aB
base class subobject, but this relation is many-to-one, likestruct C { M &m; }
.In general, for any derived class
D
(hereDeriv
), and for any virtual baseB
ofD
(hereBase
), all the base classes ofD
virtually derived fromB
(hereDeriv::D1
,Deriv::D2
) contribute to the overriding of the virtual functions in the base class:Base::F1()
is overridden byDeriv::D1::F1()
Base::F2()
is overridden byDeriv::D2::F2()
Non-virtual and virtual inheritance are very different inheritance relations, just like if non-virtual member functions and a virtual function introduce different relations between functions with the same signature in derived and base classes (hiding vs. overriding).
Like virtual and non-virtual functions, virtual and non-virtual base classes must be used in different situations (and one is not "better" than the other in general).
How to "fix" your code without virtual inheritance?
Yes: using declaration control name-lookup, so they affect visibility and ambiguity issues, not virtual functions overriding.
With your original non-virtual inheritance based design, in order to make
Deriv
a concrete class, you would have to explicitly implement bothF1()
andF2()
virtual function signatures (there are 4 virtual functions inDeriv
, but with only 2 different signatures), so you need 2 function definitions:Note that
Deriv::F1()
overridesDeriv::D1::F1()
andDeriv::D2::F1()
.