C++ template —— 动多态与静多态(六)

前面的几篇博文介绍了模板的基础知识,并且也深入的讲解了模板的特性。接下来的博文中,将会针对模板与设计进行相关的介绍。
------------------------------------------------------------------------------------------------------------
与传统的语言构造相比,模板的不同之处在于:它允许我们在代码中对类型和函数进行参数化。把(1)局部特化和(2)递归实例化组合起来,将会产生强大威力。接下来的几篇博文,我们通过下面的一些设计技术来展示这些强大威力:
(1)泛型编程
(2)trait
(3)policy class
(4)metaprogramming
(5)表达式模板

------------------------------------------------------------------------------------------------------------
第14章 模板的多态威力
多态是一种能够令单一的泛型标记关联不同特定行为的能力。对面向对象的程序设计范例而言,多态可以说是一块基石。在C++中,这块基石主要是通过继承和虚函数来实现的。由于这两个机制(继承和虚函数)都是(至少一部分)在运行期进行处理的,因此我们把这种多态称为动多态;我们平常所谈论的C++多态指的就是这种动多态。然而,模板也允许我们使用单一的泛型标记,来关联不同的特定行为;但这种(借助于模板的)关联是在编译期进行处理的,因此我们把这种(借助于模板的)多态称为静多态,从而和上面的动多态区分开来。
------------------------------------------------------------------------------------------------------------
14.1 动多态

使用继承和虚函数,在这种情况下,多态的设计思想主要在于:对于几个相关对象的类型,确定它们之间的一个共同功能集;然后在基类中,把这些共同的功能声明为多个虚函数接口。每个具体类都派生自基类,生成了具体对象之后,客户端代码就可以通过指向基类的引用或指针来操作这些对象,并且能够通过这些引用或者指针来实现虚函数的调度机制。也就是说,利用一个指向基类(子对象)的指针或者引用来调用虚成员函数,实际上将可以调用(指针或者引用实际上所代表的)具体类对象的相应成员。这种动多态是C++程序设计里面最常见的,这里不过多的阐述。

14.2 静多态 模板也能够被用于实现多态。如下例子:

// poly/statichier.hpp
#include "coord.hpp"

// 具体的几何对象类Circle
// - 并没有派生自任何其他的类
class Circle
{
    public:
        void draw() const;
        Coord center_of_gravity() const;
        ...
};

// 具体的几何对象类Line
// - 并没有派生自任何其他的类
class Line
{
    public:
        void draw() const;
        Coord center_of_gravity() const;
        ...
};
....

现在,使用这些类的应用程序看起来如下所示:

// poly/staticpoly.cpp
#include "statichier.hpp"
#include <vector>

// 画出任意GeoObj
// method2
template <typename GeoObj>
void myDraw(GeoObj const& obj)     // GeoObj是模板参数
{
    obj.draw();      // 根据对象的类型调用相应的draw()
}
......

int main()
{
    Line l;
    Circle c;

    myDraw(l);         // myDraw<Line>(GeoObj&) => Line::draw()
    myDraw(c);         // myDraw<Circle>(GeoObj&) => Circle::draw()
}

// method1:如果使用动多态,myDraw函数会是如下形式:
void myDraw(GeoObj const& obj)      // GeoObj是一个抽象基类
{
    obj.draw();
}

通过比较myDraw()的这两个实现,我们可以看出:主要的区别在于method2的GeoObj的规范是模板参数,而不是一个公共基类。然而,在这个现象的背后,还存在更多本质的差别。例如,使用动多态(method1),我们在运行期只具有一个myDraw()函数,而如果使用模板,我们则可能具有多个不同的函数,诸如myDraw<Line>()和myDraw<Circle>()。

14.3 动多态和静多态

我们来对多态进行分类,并对这两种多态进行比较。

14.3.1 术语

动多态和静多态为不同的C++编程idioms提供了支持:
(1)通过继承实现的多态是绑定的和动态的:
1. 绑定的含义是:对于参与多态行为的类型,它们(具有多态行为)的接口是在公共基类的设计中就预先确定的(有时候也把绑定这个概念称为入侵的或者插入的)。
2. 多态的含义是:接口的绑定是在运行期(动态)完成的。
(2)通过模板实现的多态是非绑定的和静态的:
1. 非绑定的含义是:对于参与多态行为的类型,它们的接口是没有预先确定的(有时也称这个概念为非入侵的或者非插入的)。
2. 静态的含义是:接口的绑定是在编译期(静态)完成的。

14.3.2 优点和缺点
(1)C++的动多态具有下列优点:
1. 能够优雅地处理异类集合;
2. 可执行代码的大小通常比较小(因为只需要一个多态函数,但对于静多态而言,为了处理不同的类型,必须生成多个不同的模板实例);
3. 可以对代码进行完全编译;因此并不需要发布实现源码(但是,分布模板库通常都需要同时发布模板实现的源代码);
(2)另一方面,C++静多态则具有下列优点:

1. 可以很容易地实现内建类型的集合。更广义地说,并不需要通过公共基类来表达接口的共同性;

2. 所生成的代码效率通常都比较高(因为并不存在通过指针的间接调用,而且,可以进行演绎的非虚拟函数具有更多的内联机会);

3. 对于只提供部分接口的具体类型,如果在应用程序中只是使用到这一部分接口,那么也可以使用该具体类型,而不必在乎该类型是否提供其他部分的接口。

通常而言,与动多态相比,静多态被认为具有更好的类型安全性:因为静多态在编译期会对所有的绑定操作进行检查。例如,假设我们尝试把一个错误类型的对象插入到一个容器中,如果这个容器是根据模板实例化而生产的话,那么几乎不会有危险,因为在编译期就可以检查出这个错误;但如果该容器所期望的元素是指向公共基类的指针,那么这些指针最后很有可能会指向不同类型的完整对象,而这就有可能会插入错误类型的对象。

在实际应用中,对于看起来相同的接口,如果在它们背后隐藏着一些语义假设的话,那么模板实例化体(静多态)有时也会导致一些问题。例如,对于一个假设具有关联运算符 + 的模板,如果基于一个没有关联该运算符的类型来实例化这个模板,那么就会出现一些问题。然而,基于继承体系的多态则很少会出现这种语义非匹配的问题,因为公共接口规范已经在基类中(更加)显式地指定了。

14.3.3 组合这两种多态

显然,你可以组合这两种形式的多态。例如,你可以从一个公共基类派生出不同种类的几何对象类,从而能够处理属于异类集合的不同几何对象。另一方面,你仍然可以使用模板来编写针对某种几何对象的代码。

在后面的博文xxxx中将进一步阐述继承和模板的组合。在第16章中,我们将看到:如何对成员函数的虚拟性进行参数化;当使用基于继承的奇异递归模板模式的时候,静多态要牺牲哪些额外的灵活性。

14.4 新形式的设计模板

这种新形式的静多态带来了实现设计模式的新方法。例如,以在C++程序设计中扮演重要角色的桥模式为例。我们使用桥模式的目的是为了能够在同一接口的多个不同实例中进行切换。我们通常可以使用一个指针来引用具体的实现,然后把所有的调用都委托给这个(包含具体实现的)类,从而达到我们的目的(见图14.3)

然而,如果实现的类型在编译期就已经是确定的,那么我们就可以借助于模板的方法来实现桥模式(见图14.4)。这将可以带来更好的类型安全性,并且也能避免使用指针,而且还能带来更高的效率。

14.5 泛型程序设计
到目前为止,在C++泛型程序设计领域中,最显著的贡献就是STL(Standard Template Library),它后来被采纳并引入到C++标准库中。STL借助于迭代器对操作进行了参数化,从而避免了操作定义在数量上的过度膨胀。在此,你并不需要为每个容器都实现每一个操作,只需要实现某个算法一次,就可以把该算法应用到每个容器中。换句话说,泛型程序设计的“粘合剂”就是:由容器提供的并且能被算法所使用的迭代器。迭代器之所以能够肩负这样的任务,是由于容器为迭代器提供了一些特定的接口,而算法所使用的正是这些接口。我们通常也把每个这样的接口称为一个concept(即约束),它说明一个模板(即容器)如果要并入这个框架(即STL),就必须履行或者实现这些约束(也即,符合STL框架标准)。
从原则上讲,也可以使用动多态来实现这些类似于STL的功能。然而,用动多态实现的功能使用起来肯定会很受限制,因为与迭代器的概念相比,动多态的虚函数调用机制将会是一种重量级的实现机制,这就会对效率产生很大的影响。譬如增加一层基于虚函数的接口层,通常就会影响操作的效率,而且这种影响的程度可能是几个数量级的(甚至更加严重)。
事实上,泛型程序设计是相当实用的,因为它所依赖的是静多态,而静多态会要求在编译期对接口进行解析。另一方面,这种要求(即对接口在编译期进行解析)还会带来一些与面向对象程序设计原则截然不同的新设计原则。

时间: 2024-08-27 21:08:22

C++ template —— 动多态与静多态(六)的相关文章

C++动多态和静多态

动多态的设计思想:对于相关的对象类型,确定它们之间的一个共同功能集,然后在基类中,把这些共同的功能声明为多个公共的虚函数接口.各个子类重写这些虚函数,以完成具体的功能.客户端的代码(操作函数)通过指向基类的引用或指针来操作这些对象,对虚函数的调用会自动绑定到你实际提供的子类对象上去. 静多态的设计思想: 对于相关的对象类型,直接实现它们各自的定义,不需要基类.只是隐式地规定各个具体类的实现中相同功能的接口名要相同.客户端把操作这些对象的函数定义为模板,你需要操作什么类型的对象,直接对模板指定该类

C++ Primer学习笔记(13)——封装、继承、多态

C++ 是一种典型的面向对象的编程语言,其最显著地特点是封装.继承和多态.充分理解封装.继承.多态是如何实现的,学好C++就不是难事了. 1.封装 封装是将多个细节元素组合在一起,隐藏起来,成为一个类.外部无法了解类内部是如何实现的,只需要考虑它的接口. 例如:将公司员工的姓名.年龄.工号等信息放在类的私有部分. 封装的好处: 避免类内部出现无意的.可能破坏对象状态的用户级错误. 随时间推移可以根据需求改变或缺陷报告来完善类实现,而无需改变用户级代码. 2.继承 该部分转自ruyue_ruyue

面经中高频知识点归纳

网易面经知识点(C++/C研发) 注:由阅读大牛面经整理而成!主要是夯实基础块! 1.多态性都有哪些? C++中的多态(虽然多态不是C++所特有的,但是C++中的多态确实是很特殊的)分为静多态和动多态(也就是静态绑定和动态绑定两种现象),静动的区别主要在于这种绑定发生在编译期还是运行期,发生在编译期的是静态绑定,也就是静多态:发生在运行期的则是动态绑定,也就是动多态.静多态可以通过模板和函数重载来实现(之所说C++中的多态主要还是因为模板这个东西),下面举两个例子:1)函数模板template

zabbix 监控 Esxi

一.下载模板 http://www.zabbix.org/wiki/Zabbix_Templates 我这边ESXI 版本是6.0的,但是模板只有5,也可以用 二.添加模板 配置 ---> 模板 ---> 载入 三.创建主机群 配置 --- 主机群组 --- 创建主机群组 四.添加主机 配置 --- 主机 ---  创建主机 选择 SNMP接口 配置宏 五.在模板中添加主机 配置 ---> 模板 ---> Template SNMP OS ESXi 六.ESXi服务器配置 启动ss

c++学习书籍推荐《C++ Templates》下载

详细讲解C++模板语言的概念. 使用C++模板的常用设计技巧. 应用例证(其中一些是"高 级"应用). 百度云及其他网盘下载地址:点我 名人推荐 如果今年你只打算买一本C++的书,那就选<C++Templates中文版>吧! --JoshWalker,ACCU成员 <C++Templates中文版>是C++世界期待已久的重量级著作. --MarcBriand,C/C++UsersJournal前任总编 一句话,模板圣经已经写就,请研习. --MaximKhesi

C++多态(静多态和动多态)

如今的C++已经是个多重泛型编程语言(multiparadigm programming lauguage),一个同时支持过程形式(procedural).面向对象形式(object-oriented).函数形式(functional).泛型形式(generic).元编程形式(metaprogramming)的语言. 这些能力和弹性使C++成为一个无可匹敌的工具,但也可能引发使用者的某些迷惑,比如多态.在这几种编程泛型中,面向对象编程.泛型编程以及很新的元编程形式都支持多态的概念,但又有所不同.

模板的多态(静多态)威力

多态是一种能够令单一泛型标记关联不同特定行为的能力,对面向对象程序设计而言多态是一块基石.C++中通过继承和虚函数实现在运行期处理这种行为的能力,我们称为动多态.然而模板也允许我们使用这种单一泛型标记来关联不同的特定行为,这种关联是在编译期间进行处理的,我们称之为静多态. 一.概念 动多态:使用继承.虚函数,基类指针实现透明地处理不同类型集合的方法(运行时多态) 静多态:使用模板参数对不同类型集合实现透明地处理的方法(编译时期多态) 二.动多态:通过继承实现的多态是绑定和动态的. 绑定的含义是:

[email&#160;protected]一个高效的配置管理工具--Ansible configure management--翻译(六)

无书面许可请勿转载 高级playbook Finding files with variables All modules can take variables as part of their arguments by dereferencing them with {{ and }} . You can use this to load a particular file based on a variable. For example, you might want to select a

Python之路【第十六篇】:Django【基础篇】

Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. 基本配置 一.创建django程序 终端命令:django-admin startproject sitename IDE创建Django程序时,本质上都是自动执行上述命令 其他常用命令: python manage.py runserver