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

转载:http://www.cnblogs.com/yyxt/p/5157517.html

前面的几篇博文介绍了模板的基础知识,并且也深入的讲解了模板的特性。接下来的博文中,将会针对模板与设计进行相关的介绍。
------------------------------------------------------------------------------------------------------------
与传统的语言构造相比,模板的不同之处在于:它允许我们在代码中对类型和函数进行参数化。把(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的功能。然而,用动多态实现的功能使用起来肯定会很受限制,因为与迭代器的概念相比,动多态的虚函数调用机制将会是一种重量级的实现机制,这就会对效率产生很大的影响。譬如增加一层基于虚函数的接口层,通常就会影响操作的效率,而且这种影响的程度可能是几个数量级的(甚至更加严重)。
事实上,泛型程序设计是相当实用的,因为它所依赖的是静多态,而静多态会要求在编译期对接口进行解析。另一方面,这种要求(即对接口在编译期进行解析)还会带来一些与面向对象程序设计原则截然不同的新设计原则。

分类: C++ Template

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机的网络体系以及参考模型

计算机的网络体系以及参考模型一、OSI七层模型二、TCP/IP参考模型三、TCP/IP 五层参考模型四、OSI 模型和 TCP/IP 模型异同比较五、OSI 和 TCP/IP 协议之间的对应关系六、为什么 TCP/IP 去除了表示层和会话层&#xff1f;七、数据如何在各层之间传输&#xff08;数据的封装过程…

C++ 模板详解(二)

转载&#xff1a;http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html 四、类模板的默认模板类型形参 1、可以为类模板的类型形参提供默认值&#xff0c;但不能为函数模板的类型形参提供默认值。函数模板和类模板都可以为模板的非类型形参提供默认值。 2、类模板的类…

C++ 模板详解(一)

转载&#xff1a;http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html C模板 模板是C支持参数化多态的工具&#xff0c;使用模板可以使用户为类或者函数声明一种一般模式&#xff0c;使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。 模板是一种对类…

剑指Offer09. 用两个栈实现队列

class CQueue { public:stack<int> stack1,stack2;CQueue() {//初始化栈while(!stack1.empty()){stack1.pop();}while(!stack2.empty()){stack2.pop();}}void appendTail(int value) {stack1.push(value);}int deleteHead() {if(stack2.empty()){while(!stack1.empty()){…

rk3588 之启动

目录 uboot版本配置修改编译 linux版本配置修改编译 启动sd卡启动制作spi 烧录 参考 uboot 版本 v2024.01-rc2 https://github.com/u-boot/u-boot https://github.com/rockchip-linux/rkbin 配置修改 使用这两个配置即可&#xff1a; orangepi-5-plus-rk3588_defconfig r…

C++引用详解

转载&#xff1a;http://www.cnblogs.com/gw811/archive/2012/10/20/2732687.html 引用的概念 引用&#xff1a;就是某一变量&#xff08;目标&#xff09;的一个别名&#xff0c;对引用的操作与对变量直接操作完全一样。 引用的声明方法&#xff1a;类型标识符 &引用名目标…

Linux网络编程服务器模型选择之循环服务器

转载&#xff1a;http://www.cnblogs.com/lizhenghn/p/3617608.html 在网络程序里面&#xff0c;通常都是一个服务器处理多个客户机&#xff0c;为了出个多个客户机的请求&#xff0c;服务器端的程序有不同的处理方式。本节开始介绍Linux下套接字编程的服务器模型选择&#xff…

剑指Offer04. 二维数组中的查找

在一个 n * m 的二维数组中&#xff0c;每一行都按照从左到右递增的顺序排序&#xff0c;每一列都按照从上到下递增的顺序排序。请完成一个高效的函数&#xff0c;输入这样的一个二维数组和一个整数&#xff0c;判断数组中是否含有该整数。 相当于二叉搜索树,左孩子比根节点小&…

Linux网络编程服务器模型选择之并发服务器(上)

转载&#xff1a;http://www.cnblogs.com/lizhenghn/p/3617666.html 与循环服务器的串行处理不同&#xff0c;并发服务器对服务请求并发处理。循环服务器只能够一个一个的处理客户端的请求&#xff0c;显然效率很低。并发服务器通过建立多个子进程来实现对请求的并发处理。并发…

Linux网络编程服务器模型选择之并发服务器(下)

转载&#xff1a;http://www.cnblogs.com/lizhenghn/p/3618986.html 前面两篇文章&#xff08;参见&#xff09;分别介绍了循环服务器和简单的并发服务器网络模型&#xff0c;我们已经知道循环服务器模型效率较低&#xff0c;同一时刻只能为一个客户端提供服务&#xff0c;而且…

Linux网络编程服务器模型选择之IO复用循环并发服务器

转载&#xff1a;http://www.cnblogs.com/lizhenghn/p/3619091.html 在前面我们介绍了循环服务器&#xff0c;并发服务器模型。简单的循环服务器每次只能处理一个请求&#xff0c;即处理的请求是串行的&#xff0c;效率过低&#xff1b;并发服务器可以通过创建多个进程或者是线…

memcpy/memset函数的c语言实现

转载&#xff1a;http://blog.csdn.net/u011118276/article/details/46742341 1、memcpy 头文件&#xff1a;#include <string.h> 函数原型&#xff1a;void *memcpy(void *dest, const void *src, size_t n) 功能&#xff1a;将指针src指向的内存空间的n个字节复制到des…

计算机网络(一)计算机网络体系

计算机网络&#xff08;一&#xff09;计算机网络体系一、计算机网络概述概念功能组成分类二、体系结构和参考模型ISO/OSI模型物理层网络层传输层会话层表示层应用层OSI参考模型与TCP/IP参考模型OSI参考模型与TCP/IP参考模型不同5层参考模型一、计算机网络概述 概念 计算机网…

计算机网络(二)物理层

计算机网络&#xff08;二&#xff09;物理层一、通信基础物理层接口特性1.机械特性2.电气特性3.功能特性4.规程特性典型的数据通信模型三种通信方式1.单工通信2.半双工通信/双向交替通信3.全双工通信/双向同时通信数据传输方式串行传输并行传输同步传输异步传输二、数据交换方…

计算机网络(三)数据链路层

计算机网络&#xff08;三&#xff09;数据链路层1.基本概念2.功能概述3.组帧字符计数法字符填充法零比特填充法违规编码法4.差错控制检错编码奇偶校验码CRC循环冗余码纠错编码海明码流量控制停止等待协议滑动窗口协议后退N帧协议&#xff08;GBN&#xff09;选择重传协议5.介质…

计算机网络(四)网络层

计算机网络&#xff08;四&#xff09;网络层一、概述和功能TCP/IP协议栈IP数据报格式IP数据报分片二、ipv4网络地址转换&#xff08;NAT&#xff09;子网划分子网掩码ARP协议&#xff08;地址解析协议&#xff09;DHCP协议ICMP协议二、ipv6ipv4和ipv6的区别IPv6基本地址类型IP…

操作系统(一)计算机系统概述

操作系统&#xff08;一&#xff09;计算机系统概述一、操作系统的概念二、功能和目标资源的管理者向上层提供服务对硬件的扩展三、操作系统的特征并发共享虚拟异步四、操作系统的发展与分类手工操作阶段批处理阶段单道批处理系统多道批处理系统分时操作系统实时操作系统操作系…

操作系统(二)进程管理

ui 操作系统&#xff08;二&#xff09;进程管理一、进程程序和进程进程控制块&#xff08;PCB&#xff09;进程的组成进程的特征进程的状态与转换进程状态的转换进程的组织链接方式索引方式进程的控制进程的创建进程的终止进程阻塞进程唤醒进程切换进程通信共享存储消息传递管…

gethostbyname()函数说明

转载&#xff1a;http://www.cnblogs.com/cxz2009/archive/2010/11/19/1881611.html gethostbyname()函数说明——用域名或主机名获取IP地址 包含头文件 #include <netdb.h> #include <sys/socket.h> 函数原型 struct hostent *gethostbyna…

操作系统(三)内存管理

操作系统&#xff08;三&#xff09;内存管理一、程序执行过程装入的三种方式链接的三种方式二、内存管理的概念内存空间的分配与回收连续分配管理方式单一连续分配固定分区分配动态分区分配首次适应算法最佳适应算法最坏适应算法邻近适应算法非连续分配管理方式基本分页存储管…