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

这篇具有很好参考价值的文章主要介绍了C++、STL标准模板库和泛型编程 ——适配器、补充(侯捷)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

侯捷 C++八部曲笔记汇总 - - - 持续更新 ! ! !
一、C++ 面向对象高级开发
1、C++面向对象高级编程(上)
2、C++面向对象高级编程(下)
二、STL 标准库和泛型编程
1、分配器、序列式容器
2、关联式容器
3、迭代器、 算法、仿函数
4、适配器、补充
三、C++ 设计模式
四、C++ 新标准
五、C++ 内存管理机制
六、C++ 程序的生前和死后

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

阶段学习
使用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

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

适配器(Adapters)

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

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

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

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

容器适配器(Container Adapters)

例如:stackqueue

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

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

仿函数适配器(Functor Adapters)

bind2nd(绑定第二实参)

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

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

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

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

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

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

not1

对一个Predicate取反。

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

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

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

bind(新型适配器)

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

C++、STL标准模板库和泛型编程 ——适配器、补充(侯捷)
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());
}

也有五种关联类型:

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

inserter

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

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

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

X适配器

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

  • 包括ostreamistream迭代器适配器

ostream_iterator

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

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

istream_iterator

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

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

C++、STL标准模板库和泛型编程 ——适配器、补充(侯捷)
copy都是已经写好的,不能再改了!

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

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

补充

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

Hash Function

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

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

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

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

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

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

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 类。

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

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进行提问。实用性不高。

C++、STL标准模板库和泛型编程 ——适配器、补充(侯捷)
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;
	...
}

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

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

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

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

cout

是一个对象object,不是一个类,源码如下:

  • 想要用cout输出自己的类型,就可以重载 << 运算符。

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

movable

movable元素会对各种容器的速度效能产生影响!!!
vector的增长方式,对vector的影响很大,对其他的容器影响不是很大!

moveable 指的是 move 构造、move 赋值

  • move():是一种浅层拷贝,当用 a 初始化 b 后,a 不再需要时,最好是初始化完成后就将 a 析构,使用 move 最优。
  • 如果说,我们用 a 初始化了 b 后,仍要对 a 进行操作,用这种浅层复制的方法就不合适了。

所以C++引入了移动构造函数,专门处理这种,用 a 初始化 b 后,就将 a 析构的情况。这种操作的好处是:

  • a 对象的内容复制一份到 b 中之后,b 直接使用 a 的内存空间,这样就避免了新的空间的分配,大大降低了构造的成本。这就是移动构造函数设计的初衷。

move的使用场景是:原来的对象不再使用。如果再用就很危险!!!

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

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

测试函数:

移动构造函数实现是:调用拷贝构造函数,但是会将原来的对象中的成员变量置0!这样就不会调用原对象的析构函数了!如下图加深的部分,而且用的是引用的引用 &&&&右值引用,右值有一个很重要的性质:只能绑定到一个将要销毁的对象。

调用移动构造函数方法,显示调用move:classObj_1(std::move(classObj_2))

move焊copy:

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

注:仅供学习参考,如有不足,欢迎指正!文章来源地址https://www.toymoban.com/news/detail-426457.html

到了这里,关于C++、STL标准模板库和泛型编程 ——适配器、补充(侯捷)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STL标准库与泛型编程(侯捷)笔记6(完结)

    本文是学习笔记,仅供个人学习使用。如有侵权,请联系删除。 参考链接 Youbute: 侯捷-STL标准库与泛型编程 B站: 侯捷 - STL Github:STL源码剖析中源码 https://github.com/SilverMaple/STLSourceCodeNote/tree/master Github:课程ppt和源码 https://github.com/ZachL1/Bilibili-plus 下面是C++标准库体系结构与内核

    2024年01月16日
    浏览(41)
  • 31 C++ 模版和泛型

    我们先来看一类问题,如下的三个方法能否换成一个方法呢? 这就是模版的来历。 所谓泛型编程,是以独立于 任何 特定类型的方式编写代码 这意味着,我们在声明或者定义的时候,不会指定具体的类型。 但是在使用的时候,需要指定具体的类型或者值 模版是泛型编程的基

    2024年02月02日
    浏览(29)
  • C++ STL 标准模板库介绍与入门

    目录 1、概述 1.1、C++ 标准库 1.2、Boost库 2、STL 版本 2.1、HP 原始版本

    2024年02月05日
    浏览(48)
  • C++——STL标准模板库——容器详解——list

    list:双向链表。list是一种分布式存储的线性表,每个节点分为数据域和指针域,其中指针域中包含一个指向前驱节点的指针和一个指向后续节点的指针,基本模型如下: 1、双向链表:每个元素都有一个前驱和一个后继,这种结构允许在链表的任何位置实现快速的插入和删除

    2024年01月16日
    浏览(37)
  • 【C++】:STL——标准模板库介绍 || string类

    STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且 是一个包罗数据结构与算法的软件框架 原始版本 Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商

    2024年02月05日
    浏览(43)
  • 一天学完C++的标准模板库STL

    提到字符串,我们会想起C语言中的 char * ,这是一个指针。而在STL中 string 也是用来声明字符串的,但是 string 是一个类,需要导入库 #includestring 。 String 封装了 char * ,管理这个字符串,是一个 char* 型的 容器 。 string 本质上是一个动态的 char 数组。 使用String字符串的第一步

    2023年04月17日
    浏览(33)
  • c++标准模板(STL)(std::array)(三)

    template     class T,     std::size_t N struct array; (C++11 起   std::array 是封装固定大小数组的容器。 此容器是一个聚合类型,其语义等同于保有一个 C 风格数组 T[N] 作为其唯一非静态数据成员的结构体。不同于 C 风格数组,它不会自动退化成 T* 。它能作为聚合类型聚合初始化,只要

    2024年02月02日
    浏览(35)
  • 【C++】——模板(泛型编程+函数模板+类模板)

    之前我们学习了函数重载,让我们在写相似函数的时候非常方便,但函数重载还有很多不足的地方,比如,每次写相似函数的时候,都要我们重新重载一个逻辑、代码几乎一样的函数,这就导致了我们的效率变低,所以我们今天来学习C++模板的相关知识点,学习完模板之后,

    2024年02月05日
    浏览(35)
  • c++ 11标准模板(STL) std::vector (二)

    template     class T,     class Allocator = std::allocatorT class vector; (1) namespace pmr {     template class T     using vector = std::vectorT, std::pmr::polymorphic_allocatorT; } (2) (C++17 起) 1) std::vector 是封装动态数组的顺序容器。 2) std::pmr::vector 是使用多态分配器的模板别名。 元素相继存储,这意味着不

    2024年02月02日
    浏览(39)
  • (AI创作实验)C++中的STL(标准模板库)

    STL概述 STL: (Standard Template Library) 标准模板库 包含一些常用的算法如排序查找,还有常用的数据结构如可变长数组、链表、字典等。 使用方便,效率较高 要使用其中的算法,需要#include C++中的STL(标准模板库)是一个非常强大的工具,为程序员提供了许多高效的数据结构和算

    2023年04月18日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包