迭代器:
迭代器就是一个类种类,通过运算符重载类种类的对象去遍历容器
迭代器的分类
正向迭代器:iterator
初始化
begin()
end()
反向迭代器reverse_iterator
rbegin()
rend()
常正向迭代器const_iterator
cbegin()
cend()
常反向迭代器const_reverse_iterator
crbegin()
crend()
按功能分类
正向迭代器
双向迭代器(可以++可以--)
随机访问迭代器
容器中迭代器分类(一般连续性内存都支持随机访问)
容器名 ????????????????? ? ?????????????????迭代器类型
array? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????随机访问(支持数组下表随机访问)
vector? ? ? ? ? ? ? ? ? ? ? ????????? ????????随机访问
deque? ? ? ? ? ? ? ? ? ? ? ????????? ????????随机访问
stack/queue/priority_queue? ? ? ? 不支持(特定顺序存储,没有迭代器)
list? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 双向
set/multiset? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 双向
map/multiset? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 双向
迭代器辅助函数
移动:advance(iterator iter,n);? ? ? ? 迭代器的移动
间距:distance(iterator begjin,iterator end);? ? ? ? 两个迭代器中间有多少个元素
交换:iter_swap(iterator first,iterator end);
拓展内容:特殊迭代器 流型迭代器(一半用在辅助打印)
输出流型:(两种构造方式)
ostream_iterator<_Ty> iter(ostream& out);
ostream_iterator<_Ty> iter(ostream& out,char* str);
输出流型迭代器做赋值运算,意味着就是打印数据到屏幕上
输入流型
istream_iterator<_Ty> iter;? ? ? ? //构造无参对象是一个错误流end_of_ostream? ? ? ?
(数据如果不满足输入格式就会返回一个错误流)
istream_iterator<_Ty> iter(istream& in);
*iter? ? ? ? 等效于cin>>操作
#include<iostream>
#include<vector>
#include<iterator>
using namespace std;
template<class _Ty>struct Node {
_Ty data;
Node<_Ty>* pNext;
Node(_Ty data) :data(data), pNext(nullptr) {};
Node(_Ty data, Node<_Ty>* pNext) :data(data), pNext(pNext) {};
};
template<class _Ty>class My_List {
public:
My_List() :frontNode(nullptr), tailNode(nullptr) {
curSize = 0;
}
void push_front(int data) {
if (curSize == 0) {
frontNode = new Node<_Ty>(data);
tailNode = frontNode;
}
else {
frontNode = new Node<_Ty>(data, frontNode);
}
curSize++;
}
void push_back() {
}
Node<_Ty>* begin() {
return frontNode;
}
Node<_Ty>* end() {
return nullptr; //返回临时变量,需要复制,准备一个拷贝构造
}
class iterator {
public:
iterator(Node<_Ty>* pmove = nullptr) :pmove(pmove) {}
iterator(const iterator& object) :pmove(object.pmove) {} //没有申请内存用浅拷贝即可
bool operator!=(Node<_Ty>* pmove)const {
return this->pmove != pmove;
}
iterator operator++(int) {//后置++需要int 但这里就不实现了
pmove = pmove->pNext;
return iterator(pmove);
}
_Ty operator*() {
return pmove->data;
}
protected:
Node<_Ty>* pmove; //迭代器实质:通过这个数据成员进行访问链表
};
void printTest() {
Node<_Ty>* pmove = frontNode;
while (pmove != nullptr) {
cout << pmove->data << "\t";
pmove = pmove->pNext;
}
cout << endl;
}
protected:
Node<_Ty>* frontNode;
Node<_Ty>* tailNode;
int curSize;
};
void testMy_List() {
My_List<int> list;
list.push_front(1);
list.push_front(2);
list.push_front(3);
list.printTest();
My_List<int>::iterator myIter = list.begin();
for (; myIter != list.end(); myIter++) {
cout << *myIter << "\t";
}
cout << endl;
}
void testIterator() {
vector<int> data = { 1,2,3,4,5,6,7,8 };
vector<int>::iterator iter;
for (iter = data.begin(); iter != data.end(); iter++) { //正反向迭代器只有++
//对象模仿指针行为
cout << *iter << "\t";
}
cout << endl;
vector<int>::reverse_iterator rIter;
rIter = data.rbegin();
//auto rIter = data.rbegin();
for (; rIter != data.rend(); rIter++) {
cout << *rIter << "\t";
}
cout << endl;
vector<int>::const_iterator c_iter;
for (c_iter = data.cbegin(); c_iter != data.cend(); c_iter++) { //不能做修改
//对象模仿指针行为
cout << *c_iter << "\t";
}
cout << endl;
}
void testExFunction() {
vector<int> data = { 1,2,3,4,5,6,7,8 };
vector<int>::iterator iter = data.begin();
advance(iter, 3);
cout << *iter << endl;
cout << "distance:" << distance(data.begin(), data.end()) << endl;
iter_swap(data.begin(), data.end() - 1);
for (auto v : data) {
cout << v << " ";
}
cout << endl;
}
void testIoIterator() {
ostream_iterator<int> iter(cout);
iter = 1243214; //就是把这串数字打印到屏幕上
cout << endl;
ostream_iterator<int> iter2(cout, "我爱你"); //一般成为别人函数参数
iter2 = 1314520; //可以批处理容器里面的数据
cout << endl;
vector<int> data = { 1,2,3,4,5,6,7,8 };
//等效打印
copy(data.begin(), data.end(), ostream_iterator<int>(cout, "\t")); //构造一个无名的
cout << endl;
//输入流型迭代器
cout << "输入;流型迭代器测试" << endl;
istream_iterator<int> end; // end_of_stream;
istream_iterator<int> in(cin);
vector<int> inputData;
while (in != end) {
inputData.push_back(*in);
++in;
}
for (auto v : inputData) {
cout << v << "\t";
}
cout << endl;
}
int main() {
//testIterator();
testMy_List();
testExFunction();
testIoIterator();
return 0;
}
Lambda表达式
Lambda:就是一个返回函数指针的表达式,它定义和返回值函数指针在一起的
Lambda表达式组成部分
//[捕获方式](函数参数)mutable exception->函数返回值类型{函数体}
int Max(int a,int b){
????????return a>b?a:b;
}
void print(){? ? ? ? //Max的Lambda表达式写法
? ? ? ? int(*pMax)(int,int)=[](int a,int b)mutable noexcept->int{
???????????????????return a>b?a:b;??
????????}
//省略写法
????????auto ppMax=[](int a,int b){
? ? ? ? ? ? ? ???return a>b?a:b;??
????????}
}
//捕获方式-->函数使用外部变量的方式
值的方式捕获????????[=]:不会影响外部变量
引用的方式捕获? ? [&]:同步到外部变量
this指针的方式? ? ? [this]:捕获类中的数据成员
不捕获任何变量? ? []
组合的捕获方式? ? [=.&x]:x用引用方式捕获,其他变量用值的方式捕获? ? ? ??
#include<iostream>
using namespace std;
void print(int(*pMax)(int, int), int a, int b) {
cout << pMax(a, b) << endl;
}
class MM {
public:
MM(string name,int age):name(name="张三"), age(age=18) {}
void print() {
[this] {cout << name << "\t" << age << endl; }(); //定义和调用一步到位,注意虽然没有参数但是调用还是要加()
}
protected:
string name;
int age;
};
int main() {
int(*pMax)(int, int) = nullptr;
pMax = [](int a, int b)mutable noexcept->int {
return a > b ? a : b;
};
cout << pMax(1, 3) << endl;
//省略版本
auto pp = [](int a, int b) {return a > b ? a : b; };
cout << pp(1, 3) << endl;
//实际使用可以一步到位 一般短暂性的局部使用的函数用lambda函数实现,如回调函数
cout << [](int a, int b)mutable noexcept->int {return a > b ? a : b; }(1, 3) << endl;
print([](int a, int b)mutable noexcept->int {return a > b ? a : b; }, 1, 3);
//捕获方式区别
//用值的方式捕获:在Lambda中不能把值当作左值使用,函数的调用不会因为值的改变而改变
int data = 101010;
auto pFunc = [=] {cout << data << endl; }; //没有参数可以把参数省略
auto pFunc2 = [&] {data,cout << data << endl; };
pFunc();
pFunc2();
data = 9999;
pFunc();
pFunc2();
MM mm("zhangsan",19);
mm.print();
//特殊的东西-->可以结合auto使用
auto pAuto = [](auto a, auto b)->auto{return a > b ? a : b; };
cout << pAuto(1, 3) << endl; //因为实际在这里展开所以可以auto不赋值[](auto a, auto b)->auto{return a > b ? a : b; }(1,3)
cout << pAuto("stringa", "stringb") << endl;
return 0;
}
仿函数
?什么是仿函数:
类模仿函数调用的行为,实质是无名对象调用重载的()函数
关键点在于重载()
一般情况仿函数是做排序准则或者一些算法的计算准则
标准库仿函数
算术类
关系类
逻辑类
选择,证同,投射
#include<iostream>
#include<string>
#include<functional> //标准库仿函数头文件
using namespace std;
class Sum {
public:
int operator()(int a, int b)const {
return a + b;
}
protected:
};
int main() {
//重载()的调用
//通过对象显示调用
Sum sum;
cout << "显示调用" << endl;
sum.operator()(1, 2);
//隐式调用
cout << "隐式调用" << endl;
sum(1, 2);
//用(){}帮助编译器解析,实质不需要
cout << "无名调用" << Sum()(1, 3) << endl; //类模仿函数调用的行为-->仿函数
//算数
cout << plus<int>{}(1, 3) << endl;
cout << minus<int>{}(1, 3) << endl;
cout << multiplies<int>{}(1, 3) << endl;
//关系
cout << equal_to<int>{}(1, 3) << endl;
cout << not_equal_to<int>{}(1, 3) << endl;
cout << greater<int>{}(1, 3) << endl;
cout << less<int>{}(1, 3) << endl;
//逻辑
cout << logical_and<int>{}(1, 3) << endl;
//大于3小于10,花里胡哨写法
int a = 34;
if (logical_and<int>{}(a > 3, a < 10)) {
cout << "这个数大于三小于十" << endl;
}
return 0;
}
函数适配器
什么是函数适配器?
用来绑定函数调用时侯的参数,让函数适应其他调用的用法。
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;
//老版本bind1st bind2nd
//新版本bind函数
int Max(int a, int b) {
return a > b ? a : b;
}
void print(int (*pMax)(int), int a) {
cout << pMax(a) << endl;
}
class Test {
public:
void print(int a, int b, int c) {
cout << a << " " << b << " " << c << endl;
}
protected:
};
void testClassFunc() {
Test test;
//注意两点1.类名取地址符,2.多一个参数,指明是哪个对象的
auto testFunc = bind(&Test::print, &test, std::placeholders::_1, std::placeholders::_2, 99);
//调用直接调用,不用对象
testFunc(1, 3);
}
void printData(int one, Test two, string str) {
cout << "调用成功" << endl;
}
//可以通过占位符,随意调整参数位置,形成不同调用形态
void testExUser() {
auto testFunc = bind(printData, std::placeholders::_3, std::placeholders::_1, std::placeholders::_2);
printData(1, Test(), "Iloveyou");
//testFunc(1, Test(), "Iloveyou"); //报错
//testFunc("ilove", 3, Test()); //报错,占位符代表的是原来的参数要去第几位
testFunc(Test(), "Iloveyou", 3);
}
int main() {
cout << Max(1, 3) << endl;
//bind返回值是函数指针
//using namespce std::placeholders
auto pMax = bind(Max,std::placeholders::_1, 100); //第一个参数是一个占位符,最多有20个占位符,把第二个参数置为100
cout << pMax(23) << endl;
cout << pMax(23,43) << endl; //第二个参数不会是43,仍然是100
//print(pMax, 23);
vector<int> vecData = { 432,34,2,36,345,6,3,76,687,45433 };
cout << count_if(vecData.begin(), vecData.end(), bind(greater<int>(), std::placeholders::_1, 60)) << endl;
cout << count_if(vecData.begin(), vecData.end(), [](int a)mutable noexcept->int {return a > 60 ; }) << endl;
testExUser();
return 0;
}
函数包装器
什么是函数包装器?
就是把函数指针包装成一个对象,通过对象调用函数。
注意点:
一旦函数指针被函数包装器包装了,那这个包装器可以直接替换函数指针用法去调用函数。
函数包装器类的实例化传参:function<函数返回值类型(参数类型)>
#include<iostream>
#include<string>
#include<functional>
using namespace std;
int Max(int a, int b) {
cout << "包装普通函数" << endl;
return a > b ? a : b;
}
class MM {
public:
void print(int a) { //成员函数在解析的时候都会传入一个this指针,而static函数不会 void print(int a,MM* mm )
cout << "包装成员函数" << endl;
}
static void printStatic() {
cout << "包装静态的函数" << endl;
}
protected:
};
class Test {
public:
void operator()(string str) {
cout << str << endl;
}
protected:
};
//结合bind函数包装
void printData(int a, MM mm, string str) {
cout << "bind和function" << endl;
}
void TestFuncBind() {
function<void(string,int,MM)> pf=bind(printData,std::placeholders::_2,std::placeholders::_3,std::placeholders::_1);
pf("string", 1, MM());
}
//包装成员函数
void testMMFunc() {
MM mm;
function<void(int)> func = bind(&MM::print, &mm, std::placeholders::_1); //结合bind函数把this指针绑在一起
func(23);
}
int main() {
function<int(int, int)> funcMax(Max);
cout << funcMax(1, 3) << endl;
function<int(int, int)> funcMax2 = Max;
function<void()> funS(MM::printStatic);
funS();
/*MM mm;
function<void()> funMM(MM::print);*/
Test test;
function<void(string)> func = test;
func("仿函数包装");
TestFuncBind();
return 0;
}
|