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

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

 学海无涯,为勤是岸

<正文开始>

  昨天晚上连上了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的自动类型推断只能运用在模版函数之中,但是对于模板函数对象,我们必须前后表明参数和函数对象的模版。

时间: 2024-10-06 06:41:55

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

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

一.笔记1.C++编程简介 2.头文件与类的声明 防卫式声明#ifndef __COMPLEX__#define __COMPLEX__ -- #endif头文件的布局模板简介template<typename T>3.构造函数 inline函数:函数若在class body内定义完成,便自动成为inline候选人 访问级别:public private被外部访问的函数设为public 构造函数complex (doble r=0,double i=0) :re(r),im(i){ }先初始化

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

前言 最近在看侯捷的一套课程<C++面向对象开发>,刚看完第一节introduction之后就被疯狂圈粉.感觉侯捷所提及所重视的部分也正是我一知半解的知识盲区,我之前也写过一些C++面向对象的程序,不过正如侯捷所说,我还仅仅停留于Object-based层面,写程序时总是在想如何封装好一个类,而不是Object-oriented强调类与类之间关系的设计. 这门课程分为两部分,第一部分讲Object-based,第二部分讲Object-oriented:第一部分又分为两部分:带指针的类的封装和不

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

vector源码1(参考STL源码--侯捷) vector源码2(参考STL源码--侯捷) #include<bits/stdc++.h> using namespace std; int main(){ vector<int> v(3,3); vector<int>::iterator it=v.begin(); cout<<v.size()<<" "<<v.capacity()<<endl;//3

侯捷访谈录摘抄-2

1.未有天才之前,应先营造天才的土壤 2.花的是自己辛苦挣来的钱,千万不要浪费在无用的东西上 3.良性循环的一个体系的建制,需从底层到顶层的坚实构筑 4.寻常一样窗前月,才有梅花便不同 5.所有同质的技术都有积累性和共同性 6.RAD的高手,无一不是有底层深厚的功力 7.基础知识的精通,是作为应用的一种过程和手段,而不是目的 8.反复读好书 9.研究Qt 10.会用STL-了解STL原理-追踪STL源码(用起来虎虎生威!) 侯捷访谈录摘抄-2,布布扣,bubuko.com

侯捷访谈录摘抄-4

1.推荐的书目 Inside Visual C++ (4th) Programming Windows 95 with MFC MFC Internals 2.DDK:撰写驱动程序(DRV)或虚拟设备驱动器(VxD),需要理解操作系统(汇编.C的天下) 3.No touch,no chance 4.提升基本功(语言能力,操作系统.数据结构.演算分析...).组织能力和文字能力 5.整理MSJ.DDJ和WDJ期刊 6.前途在自己手里 7.一台PC,可以把自己锻炼成百战金刚 8.急功近利是大忌 9.

侯捷访谈录摘抄-1

1.将coding当做一项文学的工作,代码是写给人阅读的 2.程序员要修炼得让自己对软件工程感兴趣 3.自修教育要如影随形 4.肤浅.未深刻理解技术本质会导致汲汲慌慌于新工具.新技术 5.C/C++是软件工程师的基本技能 6.人只有到了一个层次,才会思考事物的本质,不被浮面的工具所系绊 7.我们要在追求新工具和充实固有知识之间寻求平衡 8.Donuld Knuth写些不时髦的东西,却值得后代子孙记取 9.凡走过必留下足迹,现今的任何努力,只要是扎扎实实的,就绝不会落空 10.慎选好书,注意书评

侯捷访谈录摘抄-3

1.理解操作系统内部运作及各种规范与协议的基础层面 2.沉淀历练+扎实的基础才能浮升,开始抽象的思考,进行高层次的开发 3.任何工程领域之前身(或背后)一定有其科学研究或尖端研究 4.业界要的是持续稳定,保证投资和优势,MFC保持向后的兼容性也在考验着微软的智能 5.MFC的宏,自制的RTTI机制,完全符合C++标准 6.基础学问如同万古长空,IDE如一朝风月 7.不同的场合运用不同的技术才能红花绿叶相辅相成威力加乘 8.从大型卓越作品中汲取养分 9.Application Framework:

设计模式(七):Adapter 适配器模式 -- 结构型模式

1. 概述: 接口的改变,是一个需要程序员们必须(虽然很不情愿)接受和处理的普遍问题.程序提供者们修改他们的代码;系统库被修正;各种程序语言以及相关库的发展和进化.  例子1:iphone4,你即可以使用UBS接口连接电脑来充电,假如只有iphone没有电脑,怎么办呢?苹果提供了iphone电源适配器.可以使用这个电源适配器充电.这个iphone的电源适配器就是类似我们说的适配器模式.(电源适配器就是把电源变成需要的电压,也就是适配器的作用是使得一个东西适合另外一个东西.)  例子2:最典型的例

From COM to COM 侯捷 1998.06.12

摘要: 本文簡介 C++ Object Model 和 Component Object Model 的基本概念,並引介四本書籍: 1. Inside The C++ Object Model 2. Essential COM 3. Inside COM 4. Understanding ActiveX and OLE -- A Guide for Developers & Managers 將近 8 年的時間,我把自己放逐在 Windows 領域裡,縱情學習與研究.我應該算是幸運的一群人之一,