何时选择基于模板策略的设计,而不是基于非模板继承的设计
When to prefer templated policy based design over non-templated inheritance based design
我试图理解在基于策略的设计中使用模板的真正需求。通过对c++中新的模板设计的研究,我发现基于策略的类设计是一种强烈推荐的设计方式,它允许您从策略类中"插入"不同的行为。下面是一个简单的例子(wiki的缩写):
template <typename LanguagePolicy>
class HelloWorld : private LanguagePolicy
{
using LanguagePolicy::message;
public:
// Behaviour method
void run() const
{
// policy methods
cout << message();
}
};
class LanguagePolicyA
{
protected:
std::string message() const
{
return "Hello, World!";
}
};
//usage
HelloWorld<LanguagePolicyA> hello_worlda;
hello_worlda.run(); // prints "Hello, World!"
一个快速的分析表明,只是为了获得不同的可插入方法message()
,我们从一个模板类型继承,该模板类型的定义可以由任何人提供(并在编译时识别)。
但是相同级别的抽象(和可配置的方法)可以在不使用模板化代码的情况下通过简单的旧式运行时多态实现,如下所示。
class HelloWorld
{
LanguagePolicy *lp; //list of all plugable class
public:
HelloWorld(LanguagePolicy *lpn) {
lp = lpn;
}
// Behaviour method
void run() const
{
// policy methods
cout << lp->message();
}
};
class LanguagePolicy
{
protected:
virtual std::string message() const;
};
class LanguagePolicyA: LanguagePolicy
{
protected:
std::string message() const
{
return "Hello, World!";
}
};
//usage
HelloWorld helloworld(new LanguagePolicyA);
helloworld.run();
功能和抽象水平方面,我看不出这两种方法有多大区别(尽管第二种方法对LanguagePolicy
有几行额外的代码,我认为其他用户需要知道界面;否则理解LanguagePolicy
取决于文档)。但我确实认为后者是"干净的"(来自不太使用模板的人)。这是因为在我个人看来,非模板化类更易于查看和理解。一个非常好的例子是流行的库VTK(可视化工具包),它使用第二种方法解决了许多不同的问题。尽管没有广泛的文档VTK,我们大多数人-它的用户,可以看看它的类图(有时他们是相当大的),并推断类的行为;并在我们的应用程序中开发高度可配置和复杂的管道(不能将VTK成像为基于模板:))。与之相反的是像STL/BOOST这样的库,我认为任何人都不可能在不使用大量文档的情况下识别类的工作方式。
都是有效的结构化方式,这实际上取决于需求。例如
运行时与编译时多态性
你想/可以/必须在什么时候实现多态性?
虚拟调用的性能开销
模板生成没有间接指示的代码
类的实际用法。
当必须存储异构集合时,需要基类,因此必须使用继承。
一本非常好的关于基于策略的设计的书是《Modern c++ design》
我想这要看情况了。使用模板的一个可能的缺点是类型应该在编译时就知道:
HelloWorld<English> hw; // English is plugged at compile-time
在第二个示例中,使用指向基的指针,该指针可能指向各种派生类。它究竟指向什么并不需要在编译时知道,因此可以在运行时通过(用户)输入来确定。这种方法的一个可能的缺点是虚拟调用开销。在某些应用程序和某些平台上,这可能是不需要的。
- Qt - 创建主窗口前的非模态对话框
- 超级多重非虚拟继承中基类的作用域运算符
- 虚拟/非虚拟继承
- 为什么默认参数不能依赖于非默认参数?
- 为什么参数匹配适用于非模板版本,但不适用于模板版本
- §9.5.1 中的注释可以应用于非类类型吗?
- std::vector 适用于非默认可构造的类
- C++ "triangle"(而非钻石)继承
- 专用于非模板类的模板化构造函数
- 专用于非模板类的可变参数模板成员函数
- 如果将 delete[] 应用于非数组指针会发生什么情况
- 在非静态成员函数中使用时依赖于非静态成员的名称
- 混合模板/非模板继承分类和成员继承
- 虚拟和非虚拟继承的混合
- 如何将函数静态应用于非类型模板包的各个元素并对结果求和
- 自动将本地缩放应用于非全屏桌面连接(RDP 8.1及更高版本)
- 如何使非模态对话框始终在应用程序的顶部
- 非模态对话框窗口的良好设计是什么?
- 非公共C++继承在实践中的使用频率
- 为什么thread_local不能应用于非静态数据成员,以及如何实现线程本地非静态数据成员