Reputation: 51
Is it good idea to replace virtual multiple inheritance (diamon) with teplates inheritence (linear)? For example I have this class diagram :
IBase
/ \
/ \
IExtendedBase BaseImpl
\ /
ExtendedImpl
I know that I can implement it with virtual inheritance. But can I use templates in order to make this diagram linear?
class IBase
{
public:
virtual std::string name() = 0;
};
template<typename T>
class BaseImpl : public T
{
public:
virtual std::string name() override
{
return "BaseCommonImpl";
}
};
template<typename T>
class IExtendedBase : public T
{
public:
virtual std::string extended_name() = 0;
};
template<typename T>
class ExtendedBaseImpl : public T
{
public:
virtual std::string extended_name() override
{
return "ExtendedBaseImpl";
}
};
Now with typedef I can specialize ExtendedBase
typedef IExtendedBase<BaseImpl<IBase>> _ExtendedBase;
typedef ExtendedBaseImpl<_ExtendedBase> _ExtendedBaseImpl;
Which method is better? Virtual inheritance or template inheritance?
Upvotes: 0
Views: 634
Reputation: 69882
My advice would be to favour the approach that avoids multiple inheritance:
#include <iostream>
#include <string>
class IBase
{
public:
virtual std::string name() = 0;
};
class IExtendedBase : public IBase
{
public:
virtual std::string extended_name() = 0;
};
template<typename T>
class BaseImpl : public T
{
public:
virtual std::string name() override
{
return "BaseCommonImpl";
}
};
template<typename T>
class ExtendedBaseImpl : public T
{
using inherited = T;
public:
virtual std::string extended_name() override
{
return "ExtendedBaseImpl";
}
// optionally override name if you wish
std::string name() override {
return inherited::name() + "(extended)";
}
};
typedef BaseImpl<IBase> Base;
typedef ExtendedBaseImpl<BaseImpl<IExtendedBase>> ExtendedBase;
using namespace std;
int main()
{
Base a;
a.name();
cout << a.name() << endl;
ExtendedBase b;
cout << b.extended_name() << endl;
cout << b.name() << endl;
}
Upvotes: -1
Reputation: 73376
While you can obtain similar results using these two different approaches (multiple inheritance vs. template), there are important semantic differences.
Unfortunately, you do not give enough information to recommend an objective choice. So here some considerations:
Multiple inheritance approach
Multiple inheritance is meant for enforcing effective separation of concerns.
This approach should be preferred if in your case ExtendedImpl
is-a IExtendBase
and simulatneously is-a BaseImpl
, but both inheritance relations are independent.
It has the inconvenience of a slight performance overhead in some cases (casting for example).
But it has the advantage of allowing your ExtendedImpl
to be used where any of its bases could be used. And in addition, it allows for dynamic, runtime based polymorphism (if any of its base has a virtual member function).
Template approach
Templates are meant for generic programming. This approach is to be prefereed if your ExtendedImpl
is really generic, and the "bases" are more parameters for your generic concept, rather than a concept that is extended further.
Template would have here the approach of a slightly better performance (single inheritance). But you don't implement the original concept of your initial schema. And you don't have the flexibility of dynamic polymorphism.
If the relation between the types would not be of generic nature, you might induce here undesired dependencies. For example here, IExtendedBase would inherit from BaseImpl. This could be ok in many cases. But it could be completely unnatural in other cases, leading to lasting desing issues in the maintenance phase.
Conclusion
Now it's up to you to decide which advantage and inconvenience fits best your specific case. If needed, you could edit your question giving more precise indication about the context and your intentions, and I'll adapt the answer accordingly.
Upvotes: 2