多态主要是通过继承和虚函数来实现的,这两个机制都是在运行期进行处理的,因此把这种多态称为动多态。平常所谈论的C++多态指的就是这种动多态。
模板也允许使用单一的泛型标记来关联不同的特定行为,这种借助于模板的关联是在编译器进行处理的,因此把这种多态称为静多态。
动多态:
动多态的设计思想主要在于:对于几个相关对象的类型,确定它们之间的一个共同功能集,然后在基类中,把这些共同的功能声明为多个虚函数接口。
基于这种设计方案的一个典型例子是:一个用于管理某些几何形状,并且能够以某种方式对这些形状进行修改的应用程序。
对于动多态而言,最引人注目的特性或许是处理异类容器的能力。
// 画出属于异类集合的GeoObjs对象
void drawElems (std::vector<GeoObj*> const& elems)
{
for (unsigned i=0; i<elems.size(); ++i) {
elems[i]->draw(); // 根据元素的类型来调用相应的 draw()
}
}
int main()
{
std::vector<GeoObj*> coll; // 元素类型互异的集合
coll.push_back(&l); // insert line
coll.push_back(&c); // insert circle
drawElems(coll); // draw different kinds of GeoObjs
}
静多态:
可以把动多态中的myDraw()函数:
void myDraw (GeoObj const& obj)//GeoObj是一个抽象基类
{
obj.draw(); // call draw() according to type of object
}
改写为:
template <typename GeoObj>
void myDraw (GeoObj const& obj) //GeoObj是模板参数
{
obj.draw();
}
使用动多态,在运行期只具有一个myDraw()函数
使用模板,则可能具有多个不同的函数,如myDraw<Line>()和myDraw<Circle>()。
不过,静多态不允许异类集合的处理,因为所有的类型都必须能够在编译器确定。
动多态和静多态:
通过继承实现的多态是绑定的和动态的:
绑定的含义是:对于参与多态行为的类型,它们的接口是在公共基类的设计中就预先确定的
动态的含义是:接口的绑定是在运行期完成的
通过模板实现的多态是非绑定的和静态的:
非绑定的含义是:对于参与多态行为的类型,它们的接口是没有预先确定的
静态的含义是:接口的绑定在编译器完成的
各自的优点:
动多态:
能够优雅地处理异类集合
可执行代码的大小通常比较小(因为只需要一个多态函数,但对于静多态而言,为了处理不同的类型,必须生成多个不同的模板实例)
可以对代码进行完全编译;因此并不需要发布实现源码(但是,分发模板库通常都需要同时分发模板实现的源代码)
静多态:
可以很容易地实现内建类型的集合
所生成的代码效率通常比较高(因为并不存在通过指针的间接调用,而且,可以进行演绎的非虚拟函数具有更多的内联机会)
对于只提供部分接口的具体类型,如果在应用程序中只是使用到这一部分接口,那么也可以使用该具体类型,而不必在乎该类型是否提供其他部分的接口
C++ Templates:模板的多态威力
最新推荐文章于 2024-07-09 15:02:05 发布