C++ 通过模板的多重继承
将虚拟多重继承(diamon)替换为teplates继承(linear)好吗?例如,我有一个类图:C++ 通过模板的多重继承,c++,templates,inheritance,multiple-inheritance,diamond-problem,C++,Templates,Inheritance,Multiple Inheritance,Diamond Problem,将虚拟多重继承(diamon)替换为teplates继承(linear)好吗?例如,我有一个类图: IBase / \ / \ IExtendedBase BaseImpl \ / ExtendedImpl 我知道我可以通过虚拟继承来实现它。但是我可以使用模板来使这个图线性化吗 class IBase { public: virtual std::string
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";
}
};
class-IBase
{
公众:
虚拟std::string name()=0;
};
模板
类BaseImpl:public T
{
公众:
虚拟std::string name()重写
{
返回“BaseCommonImpl”;
}
};
模板
类扩展数据库:公共T
{
公众:
虚拟std::字符串扩展_name()=0;
};
模板
类ExtendedBaseImpl:public T
{
公众:
虚拟std::字符串扩展_name()覆盖
{
返回“ExtendedBaseImpl”;
}
};
现在使用typedef,我可以专门化ExtendedBase
typedef IExtendedBase<BaseImpl<IBase>> _ExtendedBase;
typedef ExtendedBaseImpl<_ExtendedBase> _ExtendedBaseImpl;
typedef IExtendedBase\u ExtendedBase;
typedef ExtendedBaseImpl _ExtendedBaseImpl;
哪种方法更好?虚拟继承还是模板继承?这个问题是一个征求意见的问题,因此可能会被主持人关闭 在此之前,我的建议是支持避免多重继承的方法:
#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;
}
#包括
#包括
IBase类
{
公众:
虚拟std::string name()=0;
};
类扩展数据库:公共IBase
{
公众:
虚拟std::字符串扩展_name()=0;
};
模板
类BaseImpl:public T
{
公众:
虚拟std::string name()重写
{
返回“BaseCommonImpl”;
}
};
模板
类ExtendedBaseImpl:public T
{
使用遗传=T;
公众:
虚拟std::字符串扩展_name()覆盖
{
返回“ExtendedBaseImpl”;
}
//如果愿意,可以选择覆盖名称
std::string name()重写{
返回继承的::name()+“(扩展)”;
}
};
typedef-BaseImpl-Base;
typedef ExtendedBase impl ExtendedBase;
使用名称空间std;
int main()
{
碱基a;
a、 名称();
cout虽然使用这两种不同的方法(多重继承与模板)可以获得相似的结果,但存在重要的语义差异
不幸的是,您没有提供足够的信息来推荐一个客观的选择。因此,以下是一些注意事项:
多重继承方法
多重继承是为了强制执行有效的
如果在您的情况下ExtendedImpl
是-aIExtendBase
,并且同时是-aBaseImpl
,但两种继承关系都是独立的,则应首选此方法
在某些情况下(例如铸造),它会带来轻微性能开销的不便
但它的优点是允许将您的extendedeimpl
用于可以使用它的任何基的地方。此外,它还允许动态的、基于运行时的多态性(如果它的任何基具有虚拟成员函数)
模板方法
模板用于泛型编程。如果您的extendedeimpl
确实是泛型的,“基”是泛型概念的更多参数,而不是进一步扩展的概念,则最好使用这种方法
在这里,模板的性能会稍好一些(单继承)。但您没有实现初始模式的原始概念。而且您没有动态多态性的灵活性
如果类型之间的关系不是泛型的,您可能会在这里产生不需要的依赖关系。例如,在这里,IExtendedBase将从BaseImpl继承。在许多情况下,这可能是正常的。但在其他情况下,这可能是完全不自然的,导致在维护阶段出现持久的设计问题
结论
现在由您决定哪种优势和不便最适合您的具体情况。如果需要,您可以编辑您的问题,给出更准确的上下文和意图指示,我将修改答案
因此。哪种方法更好?
两者都不好。这取决于。一般来说,应避免作为继承方法进行扩展,以消除这种缺陷。另请参阅《Holub on Patterns》一书因为Holub在选择实现而不是扩展方面有一些相当强烈的观点,这很有意义。多重继承只是增加了问题的数量。在我看来,你的问题似乎不是关于多重继承,而是关于一般的静态和动态继承(这是获得类似行为的完全不同的方法)。为了了解这一点,请尝试设置一个基指针向量……这对于静态方法根本不起作用。因此,通常这两种方法的组合是最方便的选择:将所有独立于派生类型的内容作为虚拟函数打包到基类中,然后从更高级别的静态继承开始一个显著的区别是:对于非模板版本,您可以使用IExtendedBase*
或IExtendedBase&
或IBase*
或IBase*
根据需要多态地处理extendedeimpl
实例,而模板意味着一个只想分派到extended\n的函数e()
需要采用IExtendedBase*
或&
类型的参数,对BaseImpl
进行编码/限制,并使该函数对从IExtendedBase
派生而非BaseImpl
的任何其他类无效,除非函数本身已模板化(通常有优化和膨胀的潜力)考虑使用。