什么时候应该使用模板而不是继承,反之亦然
When should I use templates instead of inheritance, and vice versa?
在许多情况下,这个问题甚至不会问自己,因为有时继承提供了模板无法提供的必要特性。例如,当我需要通过一个基类型(多态性)来处理不同的类型时,我需要使用继承。
然而,在某些情况下,这个问题既可以通过继承解决,也可以通过模板解决。以代码某些部分的策略模式参数化为例:
文件解析器的一个解决方案可能是这样的:
class FileParser
{
//...
public:
void Parse(ParsingAlgorithm* p);
//...
}
void FileParser::Parse(ParsingAlgorithm* p)
{
m_whatevertypeofvaluesineed = p->Parse(whateverparametersyouneed);
}
其中ParsingAlgorithm是一个抽象基类,它提供了一些基本方法,需要被任何想要为FileParser类实现特定解析器的人继承。
然而,同样可以很容易地实现使用模板:
template <class Parser>
class FileParser
{
//...
public:
void Parse()
{
m_whatevertypeofvaluesineed = m_parser.Parse(whateverparametersyouneed);
}
private:
Parser m_parser;
//...
}
是否有一些通用规则可以用来决定是使用模板还是继承?还是应该尽可能地使用模板,以避免虚拟函数之类的运行时开销?
如果您在编译时知道要操作的对象,那么使用模板的静态多态性通常是最快的方法,并且它生成的代码更简洁(不需要显式继承)。它还可以更通用,因为您不受限于强类层次结构。
如果你想要运行时多态性,那么你别无选择,只能使用指针、继承和虚函数的轻微开销。
我个人的看法:
- 尽可能使用模板,这很舒服
- 使用继承来分解代码(但不使用异构集合),但要小心切片。
- 不用担心虚拟调用的性能问题
- 有时候你没有选择,你想要异构集合拖着使用指针的痛苦
模板提供编译时多态性,而不是继承提供的运行时多态性。如果可以的话,我更喜欢使用模板。
模板通常在运行时性能更好,因为更多的工作是在编译时完成的。另一方面,它们可能更复杂,因此难以书写和理解。因此,当和不会使整个解决方案过于复杂时,最好尽可能使用它们。
对于您的示例,它们在功能上并不完全等同:第一个变体允许和要求您在运行时创建解析器的实例,而第二个变体要求解析器由程序员在编写代码时选择。
我的建议是在这种情况下都不使用,并为每种文件类型使用单独的函数;
Stream stream = open(filepath);
Image image = ParseBMP(stream);
// ...or
Image image = ParseJPG(stream);
没必要把事情弄得更复杂
相关文章:
- 继承函数的重载解析
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 带有继承的C++工厂
- 我应该避免多重实现继承吗
- C++继承更改成员
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 关于C++中具有多重继承"this"指针的说明
- 什么时候应该使用模板而不是继承,反之亦然