【发布时间】:2015-05-08 11:24:24
【问题描述】:
用模板继承(线性)替换虚拟多重继承(菱形)是个好主意吗?例如我有这个类图:
IBase
/ \
/ \
IExtendedBase BaseImpl
\ /
ExtendedImpl
我知道我可以用虚拟继承来实现它。但是我可以使用模板来使这个图表线性化吗?
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";
}
};
现在有了 typedef,我可以专攻 ExtendedBase
typedef IExtendedBase<BaseImpl<IBase>> _ExtendedBase;
typedef ExtendedBaseImpl<_ExtendedBase> _ExtendedBaseImpl;
哪种方法更好?虚拟继承还是模板继承?
【问题讨论】:
-
Which method is better?两者。两者都不。这取决于。 -
一般来说,应避免使用继承方法来消除fragile base class problem,也请参阅“Holub on Patterns”一书,因为 Holub 对选择实现而不是扩展有一些相当强烈的意见,这使得很有意义。多重继承只会增加问题。
-
在我看来,您的问题似乎不是关于 multiple 继承,而是关于一般的静态和动态继承(这是获得类似行为的完全不同的方法)。为了看到这一点,尝试设置一个基指针向量......它根本不适用于静态方法。因此,两种方法的组合通常是最方便的选择:将所有与派生类型无关的东西作为虚函数打包到基类中,然后从更高层次的静态继承开始。
-
一个显着的区别:使用非模板版本,您可以根据需要使用
IExtendedBase*或IExtendedBase&或IBase*或IBase&多态处理ExtendedImpl实例,而您的模板意味着只想调度到extended_name()的函数需要采用IExtendedBase<BaseImpl<IBase>>*或&类型的参数,编码/限制BaseImpl并使该函数对派生自IExtendedBase但不是@987654337 的任何其他类无用@/IBase,除非函数本身是模板化的(通常具有优化和膨胀的潜力)。 -
考虑改用type erasure。
标签: c++ templates inheritance multiple-inheritance diamond-problem