题外话:侯捷老师难得一年就来上九堂课就要会宝岛,特此留念签名赠语及合照以自勉。

 学海无涯,为勤是岸

<正文开始>

  昨天晚上连上了3个小时的大课探究单单讲了Adapter一个类,幸运的是本人恰好在大一的时候接触过比如<functioinal>库类中的bind1st,bind2nd这些函数对象的使用方法,毕竟若要使用<algorithm>的话,里面几乎每一个函数都需要我们把模版中的函数对象比如Comparato之类的重写一下,但是真的没有想到,这些库这些类使用起来明明那么简单但是在老师的讲解下里面的结构和设计人员的思路原来真的是复杂缜密。

  具体说Adapter(适配器)这种设计之前必须要先简单说说LSP(里氏替换原则),其内容是:子类(derived typed)必须能够替换掉它的基类(base type)。这一句话就有点让我摸不着头脑了,既然是子类已经从基类继承过来了,那岂不就是子类必然能够替换掉父类么?不然多态(polyporphism)还从和谈起?如果是在java里的话,(我觉得)也许这点是毫无争议的因为java有强大的继承体系一切类都要从Object类继承而来(lambda表达式的目标对象也不是一种类,所以不算从Object继承而来),然而在C++语言之中另有一种独特的设计--private继承,这种独特的继承方式会是父类中无论是protected还是public继承抑或是多重继承过来的指针引用都转变为子类的private数据,也就是说这些数据在继承树的这条分支上已经被宣告了终结。所以象在MFC这样的库的建立的时候LSP原则是必须遵守的,不然会给程序带来(严重的)隐患。

课件中所示,Adapter设计一般有三种(昨天只讲了两种):

(1)Container Adapter

  这个库的底层容器我们可以看到选择的是deque,值得注意的是在这套设计之中queue和deque是复合的关系,但是和我猜测的相反,queue包含了deque类也就是说queue是在deque之上架构起来的,至于为什么明明deque和(双驱)list有相同的“效果”甚至有相同的方法命名却选择了deque来作为默认的底层容器,老师谦虚地讲他也不敢下定论,但是我们至少可以大胆地推测deque的速度或者效率是优于list的。而且在这里面queue“HAS-A”deque这样的关系,在这个结构之中架构起来的更多的容器基本上都是以底层容器出发,改写方法添加约束从而完成架构。在《More Effective C++》中的编程准则之中有提到过,建议编程者将一切的数据写入private之中,但是这并不意味着这个类在继承链上部分数据的残缺,因为我们会在public或者protected中声明它们的getter&setter(是否想起了java呢:-P)来不断地继承过来对这个数据的操作权从而实现安全架构。

##stack容器的实现和queue的实现是极其相似的,这里不多赘述##

(2)Function Adapter

  这部分较上部分较难懂的,例子中的Adapter简单的来讲就是要实现一个功能:参数绑定。有的函数对象作为参数可能只需要一个参数来进行调用,但是我们这里却只用一个双参的函数对象无法直接使用作为参数,那么最效率的解决方法就是使用Adapter。当然不要自信地认为会用了这个binder系列not系列函数就是理解了Adapter,深入了解架构,才能帮助我们写出自己想要的Adapter,了解STL的规范才可以帮助我们写出的Adapter更好地与上层容器/上层对象相兼容。比如要写出一个三参绑为一个四参绑为两个这些特殊的情况才会有良好的方案去解决。

  例子是假设我们要使用count_if函数,这个函数在<algorithm>库中的作用是if xx then count计数,其中的第一个参数和第二个参数当然是Iterator类型,然而第三个参数我们需要一个单参的Predicate函数对象或者函数指针。如下图所示,其实在这里面Predicate只是template中的一个命名,它可以是T,Fxxx各种名字,但是一个Predicate的名字就可以让其他人看出这个函数对象最后需要返回的是一个布尔值,如果一旦模版实例化为一个将操作符重载为例如void operator()(Paramlist..)这样的函数时,那么在count_if内部的判断分支语言就会遇到麻烦,而且由于c++的灵活性如果将返回值重载为int /long类的话,这样count_if就不会报错程序照常执行的同时,会给貌似正确程序埋下隐患。

  那么Adapter是怎么样架构起来的呢?下面这张图很好地概括了下来。如下图所示(其实那个f和x之间按理来说应该有个逗号Anyway~)Adapter的实现过程就是在构造的时候将需要绑定的参数绑定下来,然后重载操作符使之成为一个新的函数对象。是的,貌似非常简单,但是接着向下看,如果考虑到functionAdapter是从unary_function和binary_function继承而来的模版结构的话,会大大增加复杂度,整个搭建起来adapter的过程也是不断地向父类“询问”typedef类型的过程,这些约束是adapter中最难理解的部分。

 最后我们再来看一下具体的实现宏观过程:

##课后提问##

我:在C++11的新特性中已经允许了自动类型推断,而为什么黑板上强调的bind2nd的模版类型必须和参数类型表明一致?:::(黑板)bind2nd<less<int>>(less<int>(),12)

侯捷:因为C++11的自动类型推断只能运用在模版函数之中,但是对于模板函数对象,我们必须前后表明参数和函数对象的模版。

<软件架构与设计模式>侯捷老师关于Adapter类在STL中的深入解析和模式探讨的更多相关文章

  1. Adapter类 调用Activity中的函数

    在Adapter类中可以定义一个MainActivity变量,在初始化时,对其赋值,例如fragment的适配器中: private MainActivity context; private Lis ...

  2. 侯捷老师C++大系之C++面向对象开发:(一)不带指针的类:Complex复数类的实现过程

    一.笔记1.C++编程简介 2.头文件与类的声明 防卫式声明#ifndef __COMPLEX__#define __COMPLEX__ …… #endif头文件的布局模板简介template< ...

  3. vector源码3(参考STL源码--侯捷):pop_back、erase、clear、insert

    vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷):空间分配.push_back vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 v ...

  4. vector源码(参考STL源码--侯捷):空间分配导致迭代器失效

    vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...

  5. vector源码2(参考STL源码--侯捷):空间分配、push_back

    vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...

  6. vector源码1(参考STL源码--侯捷):源码

    vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) vector源码(参考STL源码--侯捷)-----空间分配导致迭代器失效 vector源码3(参考STL源 ...

  7. 侯捷《C++面向对象开发》——动手实现自己的复数类

    前言 最近在看侯捷的一套课程<C++面向对象开发>,刚看完第一节introduction之后就被疯狂圈粉.感觉侯捷所提及所重视的部分也正是我一知半解的知识盲区,我之前也写过一些C++面向对 ...

  8. 侯捷STL学习(一)

    开始跟着<STL源码剖析>的作者侯捷真人视频,学习STL,了解STL背后的真实故事! 视频链接:侯捷STL 还有很大其他视频需要的留言 第一节:STL版本和重要资源 STL和标准库的区别 ...

  9. 侯捷STL课程及源码剖析学习3: 深度探索容器list

    一.容器概览 上图为 GI STL 2.9的各种容器.图中以内缩方式来表达基层与衍生层的关系.所谓的衍生,并非继承(inheritance)关系,而是内含(containment)关系.例如 heap ...

随机推荐

  1. struts2中怎样处理404?

    眼下在做一个网络应用程序,struts2 + spring + hibernate,server是tomcat.希望用户在IE地址栏乱敲的时候.所敲入的全部没有定义的URL都能被程序捕捉到,然后转到一 ...

  2. 1045. Favorite Color Stripe (30) -LCS同意元素反复

    题目例如以下: Eva is trying to make her own color stripe out of a given one. She would like to keep only h ...

  3. list集合转换成json类型

    public String gettext(HttpServletRequest request,HttpServletResponse response){ List<xuanhuan_> ...

  4. Ubuntu安装CodeBlocks

    访问 https://launchpad.net/~damien-moore/+archive/ubuntu/codeblocks-stable,找到页面上加粗的那一段英文(以“ppa:”开头),如“ ...

  5. 怎样在fastboot 里面加入新的命令

    fastboot 是android 默认的一种debug 方法.它的优点是在进入linux kernel 之前就可以操作. 默认fastboot 支持的命令: usage: fastboot [ &l ...

  6. 一致性哈希算法PHP测试片段

    <?php header('Content-type: text/html; charset=utf8');# 抽象接口interface hash{ public function _hash ...

  7. BFS 和 DFS

    DFS用到递归,BFS要用到一个辅助队列 #include "stdafx.h" #include<iostream> #include<vector> # ...

  8. Android BroadcastReceiver介绍 (转)

    原文地址:http://www.cnblogs.com/trinea/archive/2012/11/09/2763182.html 本文主要介绍BroadcastReceiver的概念.使用.生命周 ...

  9. Linux 在不重启的情况下识别新挂载的磁盘

    在使用 Linux 时,有时候会因为初始时磁盘空间分配估计不足,使用中需要将挂载点扩容的情况,这就需要我们挂载新的磁盘.但是如果我们在 Linux 运行过程中挂载磁盘, Linux 又不能在不重启的情 ...

  10. Lorenzo Von Matterhorn(STL_map的应用)

    Lorenzo Von Matterhorn time limit per test 1 second memory limit per test 256 megabytes input standa ...