C++模板编程(9)---模板的多型(态)威力

    所谓多型(Polymorphism),也常称为多态,是一种以单一泛化记号generic notation表述多种特定行为的能力。多型是面向对象编程思维模型object-oriented programming paradigm的基石。C++主要透过class的继承和虚拟函数(virtual function)支持多型。由于这些机制(全部或部分)生效于执行期,所以称为动态多型(dynamic polymorphism)。谈论C++多型(多态)时,所指通常都是动态多型。然而templates也允许我们以单一泛化记号表述多种特定行为,只不过一般发生在编译期,因此称为静态多型(static polymorphism)。

1. 动态多型(Dynamic Polymorphism)

      从历史上看,C++一开始只是透过继承机制与虚拟函数的结合运用来支持多型。这种背景下的多型设计关键点是:在彼此相关的object types之间确认一套共通能力,并将其声明为某共通基础类别(common base class)的一套虚拟函数接口。

    如下图,基础图元的绘制,可以定义出一个抽象基类,Abstract Base Class,ABC,GeoObj,在其中声明共同的操作operation和共同的属性properties。具体的类Circle, Line,Rectangle都继承自GeoObj。

 1)坐标文件coord.hpp

2)图元类声明头文件dynahier.hpp

 

3)具体实现代码dynapoly.cpp

 

4)测试代码主程序main.cpp

 

上述程序的关键性多型接口元素是draw() 和center_of_gravity() ,两者都是虚拟函数。上面程序中示范了它们在myDraw()、distance()和drawElems()函数内被使用的情况。由于三个函数都使用的抽象基类GeoObj,所以编译期间无法决定使用哪个版本的draw()或center_of_gravity.但是执行期间,调用虚拟函数的那个对象的完整动态类型会被获得。

    动态多型最引人注目的特性是处理异质对象群集(heterogeneous collection of objects)的能力。drawElements()阐述了这个概念:下面的简单表达式:

elems[i] -> draw()

将根据目前正在处理的元素类型,调用不同的成员函数(虽然都是draw函数)。

2. 静态多型(static Polymorphism)

 模板Templates也可以用来实现多型,然而并不依赖抽象基类来提供共性:相同的属性与操作。具体类别之间彼此独立定义。当模板实例化后,便获得了多型的威力。

                                                        多型透过模板实现示意图

例如,前面的函数myDraw():

void myDraw(GeoObj const& obj)

{

        obj.draw();

}

可以如下以模板形式改写为:

template <typename GeoObj>

void myDraw(GeoObj const& obj)

{

        obj.draw();

}

比较前后两份myDraw()实现代码,可以看出:两者的区别主要在于GeoObj如今是一个模板参数template parameter而非一个common base class。然而在此表象背后,还有一些更根本的区别。

如果使用动态多型,执行期间只会有一个myDraw()函数,但如果使用template,我们会拥有不同的函数,如myDraw<Line>() 和myDraw<Circle>()。

现在基于静态多型机制要改写独立的几何类别:

classes的应用程序看起来像如下模样:

 

测试主程序如下:

 

3. 动态多型与静态多型的对比

    动态多型和静态多型支持不同的C++编程手法(idioms):

    经由继承而实现的多型是bounded(绑定的)和动态的dynamic

绑定意味着参与多型行为的类型,其接口系透过common base class 的设计而预先定妥的。此概念的另一些描述术语为invasive侵略性的或intrusive侵入式的。

dynamic意味着接口的绑定动态完成与执行期。

形成对比的是,

经由templates而实现的多型是unbounded(非绑定的)和静态的static

unbounded意味着参与多型行为的类型,其接口并非预先决定好的。此概念的另一些描述术语有:

noninvasive或nonintrusive非侵入式的。

static意味着接口的绑定静态完成于编译期间。

因此严格说来,动态多型和静态多型分别是绑定之动态多型和未绑定之静态多型。

4. 设计模式的新形式

静态多型为设计模式带来了新的实现形式,举个bridge范式为例子,

引入模板后,静态多型实现如下,

 

5. 泛型编程

    静态多型带来了泛型编程的概念。然而并不存在被普通认同的泛型编程定义。众多定义的根源是:使用泛化参数generic parameters进行编程,以便找出高效算法之最抽象表述。那本书最后总结如下:

    泛型编程是一个计算器科学分支,适合用来找出(发现)高效算法、数据结构、其他软件概念之抽象表述,并用处理它们的系统化组织方式。泛型编程主要用于表现(领域概念)族系。

    在C++环境中,泛型编程有时被定义为以模板进行编程(而面向对象编程则被认为是以虚拟函数进行编程)。从这个意义上讲,只要使用了C++ templates,任何编程行为都可以视为泛型编程。

    迄今为止,这个领域中最耀眼的贡献是STL(Standard Template Library)。STL是个框架(framework),提供大量有用的操作,称为算法(algorithms),以及大量用于处理对象群集(collections of object)的线性数据结构,称为容器(containers)。算法和容器都是templates。不过最关键的还在于:算法并非容器的成员函数,而是以某种泛化方式编写而成,因此可被任何容器所用。为了做到这一点,STL设计者确认了一个抽象概念:迭代器(iterators)

6. 小结

   容器类型时将模板引入C++编程语言的首要动机。templates出现之前,多型阶层体系polymorphic hierarchy是处理容器的流行方式,一个较为流行的例子是NIHCL,National Institutes of Health Class Library,如下图,

    静态多型适合编写十足的基础计算结构。相形之下,动态多型需要选择一个共通基础类型common base type,意味着其库往往是领域专属的domain-specific。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值