• 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。 

  • 相关阅读:
    vue3学习源码笔记(小白入门系列)------provide和 inject 跨层级数据传递原理
    【刷爆LeetCode】七月算法集训(29)分而治之
    什么是C语言中的命名空间?
    【JavaScript】浅拷贝与深拷贝
    八大排序算法汇总(C语言实现)
    [postgres]配置主从异步流复制
    tf.compat.v1.global_variables
    C++ Among Us 太空狼人杀(上半部分)
    【安装tensorflow-CPU版本】
    蓝桥等考C++组别一级009
  • 原文地址:https://blog.csdn.net/zkmrobot/article/details/125457495