C++、STL标准模板库和泛型编程 ——适配器、补充(侯捷)

news2024/12/25 1:59:52

C++、STL标准模板库和泛型编程 ——适配器 (侯捷)--- 持续更新

  • 适配器(Adapters)
    • 容器适配器(Container Adapters)
    • 仿函数适配器(Functor Adapters)
      • bind2nd(绑定第二实参)
      • not1
      • bind(新型适配器)
    • 迭代器适配器(Iterator Adapters)
      • reverse_iterator
      • inserter
    • X适配器
      • ostream_iterator
      • istream_iterator
  • 补充
    • Hash Function
    • tuple
    • type traits
    • cout
    • movable

使用一个东西,却不明白它的道理,不高明!—— 林语堂

阶段学习
使用C++标准库
认识C++标准库(胸中自有丘壑!)
良好使用C++标准库
扩充C++标准库

所谓 Generic ProgrammingGP,泛型编程),就是使用 template (模板)为主要工具来编写程序。

  • GP 是将 datasmethods 分开来;

    • ContainersAlgorithms可各自闭门造车﹐其间以Iterator连通即可·
    • Algorithms通过Iterators确定操作范围﹐也通过Iterators取用 Container元素。
  • OOP(Object-Oriented Programming),企图将 datasmethods 关联在一起。

C++标准模板库Standard Template 最重要的六大部件(Components):容器算法仿函数迭代器适配器分配器

  • 容器(Containers)是class template
  • 算法(Algorithms)是function template其内最终涉及元素本身的操作,无非就是比大小!)
  • 迭代器(Iterators)是class template
  • 仿函数(Functors)是class template
  • 适配器(Adapters)是class template
  • 分配器(Allocators)是class template

关系图:
在这里插入图片描述

适配器(Adapters)

可以把它理解为改造器,它要去改造一些东西;也可以理解为实现换肤功能

已经存在的东西,改接口,改函数名等。。。

在这里插入图片描述

实现适配,可以使用继承(is a)复合(has a) 的两种方式实现。
共性:STL使用 复合(has a) 来实现适配!

容器适配器(Container Adapters)

例如:stackqueue

具体定义查看:序列式容器的stackqueue容器

  • 只使用一部分以及改接口,改函数名等。。。
  • 复合(内涵) 的东西换一个风貌换一种风格出来!

仿函数适配器(Functor Adapters)

bind2nd(绑定第二实参)

把东西记起来,以备后面使用!

可以看到下面的这个例子,使用算法count_if:

  • 第三个参数是一个predicate,也就是判断条件,有一个仿函数对象less<int>(),但是他被仿函数适配器bind2nd(将less的第二个参数绑定为 40)和 not1(取反)修饰,从而实现判断条件为是否小于40

在这里插入图片描述
bind2nd调用binder2nd:

  • 图上灰色的东西就是仿函数适配器仿函数之间的问答
    • 这里就体现了仿函数为什么要继承适合的unary_function或者binary_function等类的原因!
  • 还有一个细节:适配器适配之后的仿函数也能够继续被适配:
    • 所以适配器要继承unary_function或者binary_function等类,这样才能回答另外一个适配器的问题。
    • 问 bianry_fucntion 三个参数first_argument_typesecond_argument_typeresult_type
    • 提问前面都要加上typename,是为了让编译通过!
  • 所以,仿函数必须能够回答适配器的问题,这个仿函数才是可适配的!

相对绑定第二实参,绑定第一实参bind1st

not1

对一个Predicate取反。

  • not1是构造一个与谓词结果相反的一元函数对象。
  • not2是构造一个与谓词结果相反的二元函数对象。

一层套一层,像乐高积木一样!

在这里插入图片描述

bind(新型适配器)

替换了一些过时(bind1st、bind2st)的仿函数适配器!

在这里插入图片描述
std::bind 可以绑定:

  1. functions
  2. function objects
  3. member functions_1(占位符号)必须是某个object地址。
  4. data members_1必须是某个object地址。

返回一个function object ret。调用ret相当于调用上述的1,2,3或者相当于取出4.

示例:

// bind example
#include <iostream>     // std::cout
#include <functional>   // std::bind

// a function: (also works with function object: std::divides<double> my_divide;)
double my_divide (double x, double y) {return x/y;}

struct MyPair {
  double a,b;
  double multiply() {return a*b;}
};

int main () {
  // 占位符的使用方法!!!!!!!!
  using namespace std::placeholders;    // adds visibility of _1, _2, _3,...
  
  //---------------------绑定function,也就是前面的1---------------------
  // binding functions:
  auto fn_five = std::bind (my_divide,10,2);               // returns 10/2
  std::cout << fn_five() << '\n';                          // 5

  auto fn_half = std::bind (my_divide,_1,2);               // returns x/2
  std::cout << fn_half(10) << '\n';                        // 5

  auto fn_invert = std::bind (my_divide,_2,_1);            // returns y/x
  std::cout << fn_invert(10,2) << '\n';                    // 0.2

  auto fn_rounding = std::bind<int> (my_divide,_1,_2);     // returns int(x/y)
  std::cout << fn_rounding(10,3) << '\n';                  // 3

  MyPair ten_two {10,2};

  //---------------------绑定member functions,也就是前面的3---------------------
  // binding members:
  //member function 其实有一个看不见的实参argument :this
  auto bound_member_fn = std::bind (&MyPair::multiply,_1); // returns x.multiply()
  std::cout << bound_member_fn(ten_two) << '\n';           // 20

  //---------------------绑定member data,也就是前面的4---------------------
  auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.a
  std::cout << bound_member_data() << '\n';                // 10


  //-------------------------上面的bind2nd就可以替换了-------------------------
  vector<int> v {15, 37, 94, 50, 73, 58, 28, 98};
  int n = count_if(v.cbegin(), v.cend(), not1(bind2nd(less<int>(), 50)))
  cout << "n=" << n << endl; //5

  //替换
  auto fn_ = bind(less<int>(), _1, 50);
  cout << count_if(v.cbegin(), v.cend(), fn_) << endl;   //3
  
  return 0;
}

迭代器适配器(Iterator Adapters)

reverse_iterator

reverse_iterator
rbegin(){//取逆向的头,就是正向的尾巴
	return reverse_iterator(end());
}
	
reverse_iterator
rend(){//取逆向的尾巴,就是正向的头
	return reverse_iterator(begin());
}

也有五种关联类型:

在这里插入图片描述

inserter

可以不用担心copy到的目的容器大小不匹配的问题。
copy是写死的,我们调用copy,希望完成在容器指定位置插入一些值!具体的实现:

  • 把相应的容器和迭代器传入inserter,对容器的迭代器中的 = 运算符进行重载,就能改变copy的行为!
  • 因为这个是对迭代器的 = 运算符行为进行重定义,所以是迭代器的适配器

在这里插入图片描述

X适配器

X表示未知:(容器迭代器函数,三大类之外的!)

  • 包括ostreamistream迭代器适配器

ostream_iterator

  • copy都是已经写好的,不能再改了!
  • 该适配器适配的是basic_ostream,也是重载了 = 运算符,添加输出操作

在这里插入图片描述

istream_iterator

ostream_iterator的兄弟,cin >> x被替换为了 x = *iit ,适配 basic_istream

  • 不断++,就不断读内容。

在这里插入图片描述
copy都是已经写好的,不能再改了!

当创建iit(cin),已经读入数据了!
不断++,就不断读内容。

在这里插入图片描述

补充

标准库STL周边还有一些东西需要知道。

Hash Function

如果有一个我们自己的类,我们要怎么给这个类设计hash函数呢?

在这里插入图片描述

使用类中的成员变量的hash函数得到hash值,然后相加,(下面左上角)这个太naive了,可能会产生很多冲突。
所以使用右边那个!

  • args是C++11的新特性,任意多个参数都行,n个参数的args作为另外一个函数的输入的时候
    • 先调用①,分配一个种子seed,再调用②;
    • 在②里面拆分args,拆分成1 + n-1 的形式,递归调用自身,直到args只剩下一个参数时,调用③;
    • 在②中拆分时,会不断改变种子seed基本类型的hash函数 + 0x9e3779b9 + ... (越乱越好,没有数学可言,)。

也是使用想法一的思想,但是加入了更多的复杂的操作,使得得到的hash code冲突更少。

在这里插入图片描述

tuple

一组东西的组合,可以任意指定多少个元素,这些元素可以是任意的类型。

使用示例:

tuple<string, int, int, complex<double>> t;
sizeof(t); // 32, 为什么是32,而不是28呢?啊~侯捷也无法理解啊!

tuple<int, float, string> t1(41, 6.3, "test");
cout << "t1:" << get<0>(t1) << ' ' << get<1>(t1) << ' ' << get<2>(t1) << endl;

auto t2 = make_tuple(22, 44, "test2"); // t2也是一个tuple,自动推导类型

tuple_size< tuple<int, float, string> >::value; // 3
tuple_element< tuple<int, float, string> >::type; // 取tuple里面的类型

继承的是自己,会自动形成一个类的继承关系,注意有一个空的 tuple 类。

在这里插入图片描述

type traits

trivial:琐碎的,平凡的,平淡无奇的,无关痛痒的,无价值的,不重要的。

泛化模板类,包括五种比较重要的typedef: 默认的回答都是重要的!

typedef _false_type has_trivial_default_constructor; 		//默认构造函数是不重要吗?
typedef _false_type has_trivial_copy_constructor;			//拷贝构造函数是不重要嘛?
typedef _false_type has_trivial_assignment_operator;		//拷贝赋值构造函数是不重要嘛?
typedef _false_type has_trivial_destructor;					//析构函数是不重要嘛?
typedef _false_type is_POD_type;							//是不是旧格式(struct,只有数据,没有方法)?

比如说对于inttype traits五个问题的回答都不重要。一般是算法会对traits进行提问。实用性不高。

在这里插入图片描述
type traits

现在的 traits机 ,非常智能:

  • 只要把自己写的或者系统自带的类,作为 is_()::value 就能得到问题的答案,这些问题包括下面几种,不全:

测试:

//global function template
template <typename T>
void type_traits_output(const T& x)
{
	cout << "\ntype traits for type:" << typeid(T).name() << endl;
	
	cout << "is_void\t" << is_void<T>::value << endl;
	cout << "is_integral\t" << is_integral<T>::value << endl;
	cout << "is_array\t" << is_array<T>::value << endl;
	cout << "is_class\t" << is_class<T>::value << endl;
	cout << "is_function\t" << is_function<T>::value << endl;
	cout << "is_pointer\t" << is_pointer<T>::value << endl;
	cout << "is_object\t" << is_object<T>::value << endl;
	...
}

在这里插入图片描述
在这里插入图片描述

类型萃取机这么强的功能,是怎么实现的呢?下面以is_void为例:

  • 首先去掉 constvolatile 这两种对得到类特征无用的修饰关键字,做法如下(主要是用模板技巧);
  • 然后将去掉 cv (就是constvolatile )关键字之后,再传入 __is_void_helper 模板类中,让其自己匹配是不是空类型,匹配到不同的模板类,返回不同的bool值。

在这里插入图片描述

cout

movable

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

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

相关文章

Tomcat源码:Pipeline与Valve

参考资料&#xff1a; 《Tomcat组成与工作原理》 《Tomcat - Container的管道机制&#xff1a;责任链模式》 《Tomcat源码解析系列 Pipeline 与 Valve》 前文&#xff1a; 《Tomcat源码&#xff1a;启动类Bootstrap与Catalina的加载》 《Tomcat源码&#xff1a;容器的生命…

Mybatis源码01-Executor

前言 为了方便公司业务排查问题&#xff0c;要求打印执行的sql&#xff0c;以及执行时间。编写了一个Mybatis的拦截器&#xff0c;此前从未看过mybatis的源码&#xff0c;在调试的过程中不断阅读源码&#xff0c;后边想更深刻了解一下&#xff0c;看了鲁班大叔的视频&#xff…

OSCP-Nickel(爆破pdf、本地http提权)

目录 扫描 HTTP 提权 扫描 FileZilla不接受匿名FTP登录。 端口21上的SSH和3389上的RDP很少是初始入口点,但是如果遇到一些凭据,可以记住这一点。 HTTP 打开Web浏览器并导航到端口8089和3333,用于的HTTP服务器。端口8089似乎是某种类型的开发环境。 单击一个按钮重定向到…

boot-admin整合Quartz实现动态管理定时任务

淄博烧烤爆红出了圈&#xff0c;当你坐在八大局的烧烤摊&#xff0c;面前是火炉、烤串、小饼和蘸料&#xff0c;音乐响起&#xff0c;啤酒倒满&#xff0c;烧烤灵魂的party即将开场的时候&#xff0c;你系统中的Scheduler&#xff08;调试器&#xff09;&#xff0c;也自动根据…

在函数中使用变量

shell脚本编程系列 向函数传递参数 函数可以使用标准的位置变量来表示在命令行中传给函数的任何参数。其中函数名保存在$0变量中&#xff0c;函数参数则依次保存在$1、$2等变量当中&#xff0c;也可以使用特殊变量$#来确定参数的个数 在脚本中调用函数时&#xff0c;必须将参…

day3 TCP/IP协议与五层体系结构

TCP / IP 四层体系结构 TCP / IP工作流程&#xff1a; 现在互联网使用的 TCP/IP 体系结构已经发生了演变&#xff0c;即某些应用程序可以直接使用 IP 层&#xff0c;或甚至直接使用最下面的网络接口层。 沙漏型展示&#xff1a; 五层体系结构 各层的主要功能 应用层&#xff1…

C++ Primer阅读笔记--语句的使用

① 空语句 最简单的语句是空语句&#xff0c;其只含有一个单独的分号&#xff1b; ② switch语句 case 关键字和它对应的值一起被称为 case 标签&#xff0c;case 标签必须是整型常量表达式&#xff1b; char ch getVal(); int iVal 42; switch(ch){case 3.14: // 错误&#…

ZmosHarmony buildroot移植与使用

前言 移植过程 1、添加编译选项编译buildroot。 2、开机启动时设置 LD库的环境变量与PATH路径。 是什么原因需要这样操作&#xff1f; 主要使用busybox&#xff0c;使用buildroot的瑞士军dao。 使用busybox 为buildroot下的使用 第一次启动时设置 由于是在vendor分区因此 …

01 openEuler虚拟化-KVM虚拟化简介

文章目录 01 openEuler虚拟化-KVM虚拟化简介1.1 简介1.2 虚拟化架构1.3 虚拟化组件1.4 虚拟化特点1.5 虚拟化优势1.6 openEuler虚拟化 01 openEuler虚拟化-KVM虚拟化简介 1.1 简介 在计算机技术中&#xff0c;虚拟化是一种资源管理技术&#xff0c;它将计算机的各种实体资源&…

ActiveMQ 反序列化漏洞 (CVE-2015-5254)漏洞复现

当前漏洞环境部署在vulhub,当前验证环境为vulhub靶场&#xff08;所有实验均为虚拟环境&#xff09; 实验环境&#xff1a;攻击机----kali 靶机&#xff1a;centos7 需要的jar包&#xff1a;jmet-0.1.0-all.jar 1、启动docker&#xff0c;进入vulhub&#xff08;靶机&#xff0…

centos主机测试io极限

这里使用fio工具来测试磁盘的io 1.安装fio命令 yum -y install fio 2.在需要测试的磁盘所挂载的目录下创建一个测试目录 由于我就只有一个磁盘&#xff0c;/目录也挂载在这个磁盘上&#xff0c;所以就直接在tmp目录里创建 mkdir /tmp/cs 3.创建一个名为 test.fio 的文件&a…

中级软件设计师备考---信息系统安全

目录 安全属性对称加密技术非对称加密技术信息摘要和数字签名数字信封和PGP各个网络层次的安全保障网络威胁与攻击防火墙技术 安全属性 保密性&#xff1a;最小授权原则、防暴露、信息加密、物理保密 完整性&#xff1a;安全协议、校验码、密码校验、数字签名、公证 可用性&a…

【 Spring 事务传播机制 】

文章目录 一、概念二、为什么需要事务传播机制&#xff1f;三、事务传播机制有哪些&#xff1f;四、Spring 事务传播机制使⽤和各种场景演示4.1 ⽀持当前事务&#xff08;REQUIRED&#xff09;4.2 不⽀持当前事务&#xff08;REQUIRES_NEW&#xff09;4.3 NESTED 嵌套事务4.4 嵌…

软考软件设计师 软件工程笔记

软件工程 CMM&#xff08;能力成熟度模型&#xff09;CMMI&#xff08;能力成熟度模型集成&#xff09;瀑布模型V模型&#xff08;质量保证&#xff09;增量模型演化模型&#xff08;迭代更新&#xff09;原型模型螺旋模型&#xff08;风险分析&#xff09;喷泉模型统一过程&am…

大数据编程实验二:熟悉常用的HDFS操作

实验目的 1、理解HDFS在Hadoop体系结构中的角色 2、熟悉使用HDFS操作常用的Shell命令 3、熟悉HDFS操作常用的Java API 实验平台 1、操作系统&#xff1a;Windows 2、Hadoop版本&#xff1a;3.1.3 3、JDK版本&#xff1a;1.84、Java IDE&#xff1a;IDEA 实验步骤 前期&#x…

Springboot整合WebSocket(纯后端)

文章目录 一、 HTTP协议与WebSocket区别二、客户端&#xff08;浏览器&#xff09;实现1、websocket对象2、websocket事件3、WebSocket方法 三、服务端实现1、连接过程2、服务端接收客户端消息3、服务端推送消息给客户端 四、后端功能实现 一、 HTTP协议与WebSocket区别 HTTP协…

如何在家自学编程成为一名程序员?

转自&#xff1a;如何在家自学编程&#xff0c;成为一名优秀的程序员&#xff1f; - 知乎 跟着黑马程序员学&#xff0c;自学也可以很优秀。先找到方向—>前/后端&#xff1f;测试&#xff1f;还是什么&#xff1f;—>找到相关的学习路线 —> 坚持不懈的学习 —> …

论文学习——Video LDM (Align your Latents)

Align your Latents: High-Resolution Video Synthesis with Latent Diffusion Models 0. 来源 本文是阅读论文后的个人笔记&#xff0c;适应于个人水平&#xff0c;叙述顺序和细节详略与原论文不尽相同&#xff0c;并不是翻译原论文。 如果想了解所有细节&#xff0c;建议移…

华为OD机试真题(Java),旋转数组的最小数字(100%通过+复盘思路)

一、题目描述 有一个长度为 n 的非降序数组&#xff0c;比如[1,2,3,4,5]&#xff0c;将它进行旋转&#xff0c;即把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;变成一个旋转数组&#xff0c;比如变成了[3,4,5,1,2]&#xff0c;或者[4,5,1,2,3]这样的。请问&#xf…

Filter 的使用

把对资源的请求拦截下来&#xff0c;从而实现一些特殊功能 &#xff0c;比如需要先登录再使用其他功能 拦截对资源的请求 放行后&#xff0c;执行完资源&#xff0c;再执行放行后的逻辑 按字符比较升序排序&#xff0c;值小的优先级高 FilterDemo优先级高于FilterDemo2 Listene…