文章目录

  • ​​1.适配器​​
  • ​​2.函数适配器​​
  • ​​3.针对成员函数的函数适配器​​

1.适配器

  • 三种类型的适配器:容器适配器,迭代器适配器,函数适配器
  • 容器适配器:用来扩展7种基本容器,利用基本容器扩展形成了栈、队列和优先级队列
    利用现有容器扩展而成,所以称之为容器适配器
  • 迭代器适配器:(反向迭代器、插入迭代器、IO流迭代器)
    反向迭代器利用正向迭代器来实现的;
    插入迭代器在遍历的过程中可以插入数据;
    IO流迭代器可以遍历IO流对象;
  • 函数适配器:函数适配器能够将仿函数和另一个仿函数(或某个值、或某个一般函数)结合起来。

2.函数适配器

  • 函数适配器:函数适配器能够将仿函数和另一个仿函数(或某个值、或某个一般函数)结合起来。
  • eg:P83\01.cpp
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;
bool is_odd(int n)
{
return n % 2 == 1;
}

int main(void)
{
int a[] = {1,2,3,4,5};
vector<int> v(a, a+5);

//算法可以适用于容器的
//统计向量中奇数的个数
cout<<count_if(v.begin(), v.end(), is_odd)<<endl;
return 0;
}
  • 测试:
  • (P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_后端

  • eg:P83\02.cpp
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;
bool is_odd(int n)
{
return n % 2 == 1;
}

int main(void)
{
int a[] = {1,2,3,4,5};
vector<int> v(a, a+5);

//算法可以适用于容器的
//统计向量中奇数的个数
count<<count_if(v.begin(), v.end(), is_odd)<<endl;


//计算奇数元素的个数
// 这里的bind2nd将二元函数对象modulus转换为一元函数对象。
//modulus本来的参数接收2个参数:m%n,
//bind2nd只需要接受一个参数了,因为他绑定了第2个参数,m%2,此时一元函数对象有状态了,保存的是2的状态
//而m的参数从v.begin(), v.end()中来
//bind2nd(op, value) (param)相当于op(param, value)
//bind2nd(二元函数对象,是要绑定的值),返回一元函数对象,返回一个参数param
//param是v.begin(), v.end(),遍历过程中,将值传递到param里面的

//bind2nd是一个函数模板
cout << count_if(v.begin(), v.end(),
bind2nd(modulus< int>(), 2)) << endl;

return 0;
}
  • 测试:
  • (P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_函数对象_02

  • 断点:
bind2nd(modulus< int>(),  2)) << endl;

返回值是一元函数对象

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_c++_03


F11,看下构造函数,第一个参数是二元函数对象,第二个参数是要绑定的值

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_#include_04


为什么说binder2nd是一元函数对象?

因为他继承至unary_function

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_c++_05


重载()运算符,只接受一个参数说明他是一元函数对象

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_c++_06

  • eg:P83\03.cpp
  • 测试:
  • (P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_#include_07

3.针对成员函数的函数适配器

  • 将类的成员函数转换为函数对象
  • eg:P83\04.cpp
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <string>

using namespace std;

class Person
{
public:
Person( const string &name) : name_(name) {}
void Print() const
{
cout << name_ << endl;
}
void PrintWithPrefix(string prefix) const
{
cout << prefix << name_ << endl;
}
private:
string name_;
};

void foo( const vector<Person> &v)
{
//for_each接收的是一元的函数对象
// mem_fun_ref将不带参数的成员函数转换成一元函数对象,将print()成员函数转换成立一元函数对象
// mem_fun_ref是一个函数适配器
for_each(v.begin(), v.end(), mem_fun_ref(&Person::Print));
//mem_fun_ref将带一个参数的成员函数转换成二元函数对象
//称之为:mem_fun_ref函数模板的类型自动推导功能,可以根据传递进来的参数进行类型推导
for_each(v.begin(), v.end(), bind2nd(mem_fun_ref(&Person::PrintWithPrefix), "person: "));
}

void foo2( const vector<Person *> &v)
{
//mem_fun_ref用于容器里面的元素是对象
//mem_fun用于容器里面的元素是指针
for_each(v.begin(), v.end(), mem_fun(&Person::Print));
for_each(v.begin(), v.end(), bind2nd(mem_fun(&Person::PrintWithPrefix), "person: "));
}

int main( void)
{
vector<Person> v;
v.push_back(Person( "tom"));
v.push_back(Person( "jerry"));
foo(v);

//向量中存放的是对象指针
vector<Person *> v2;
v2.push_back( new Person( "tom"));
v2.push_back( new Person( "jerry"));
foo2(v2);
return 0;
}
  • 断点:
for_each(v.begin(), v.end(), mem_fun_ref(&Person::Print));

函数适配器mem_fun_ref,形式上来看是一个函数模板,(_Ty::\*_Pm)() const表示类里面的不带参数的成员函数,且是const的成员函数,

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_#include_08


F11,_Pm表示将Person::Print的成员函数传递进来

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_后端_09


F11,说明mem_fun_ref是一元函数对象。

调用构造函数发现,他将成员函数的地址保存到_Pmemfun。

重载了调用运算符(),_Left表示Person对象,然后调用他的成员函数

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_开发语言_10

  • 断点:
for_each(v.begin(), v.end(), bind2nd(mem_fun_ref(&Person::PrintWithPrefix),  "person: "));

都是模板,构成重载

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_函数对象_11


这是一个二元的函数对象,_Left传递进来的是一个类对象,_Right传递进来的是一个参数

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_#include_12

  • 区别在于是对象还是对象指针
  • 断点:
for_each(v.begin(), v.end(), mem_fun(&Person::Print));

将不带参数的成员函数转换成一元函数对象

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_开发语言_13


F11,通过指针来调用成员函数

(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_#include_14

  • 测试:
  • (P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_开发语言_15

  • 对一般函数的函数适配器
    eg:P83\05.cpp
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <string>

using namespace std;

int main( void)
{
char *a[] = { "", "BBB", "CCC"};
vector< char *> v(a, a + 2);
vector< char *>::iterator it;
//ptr_fun转换成二元的函数对象,a,b,最后是strcmp(value, ""),如果是空字符串,比较返回0,为假
//find_if是判别式为非0的时候,才是我们需要的
// bind2nd转换成一元函数对象
it = find_if(v.begin(), v.end(), bind2nd(ptr_fun(strcmp), ""));//查找第一个不是空串的字符串
if (it != v.end())
cout << *it << endl;

return 0;
}
  • 测试:
  • (P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_开发语言_16

  • eg:P83\06.cpp
#include  <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <string>

using namespace std;

bool check( int elem)
{
return elem < 3;
}

int main( void)
{
int a[] = { 1, 2, 3, 4, 5};
vector< int> v(a, a + 5);

vector< int>::iterator it;
// not1中的no说明是>=3,取反
// not1也是一个一元函数对象
it = find_if(v.begin(), v.end(), not1(ptr_fun(check)));//返回第一个>=3的元素

//不能这么写的原因是:因为类型不匹配, not1需要有argument_type,而check函数没有
//ptr_fun是一个函数适配器,将普通函数转换成一元函数对象,这样与not1的接口能匹配了
// it = find_if(v.begin(), v.end(), not1(check);
if (it != v.end())
cout << *it << endl;
return 0;
}
  • 测试:
  • (P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_开发语言_17


  • (P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_开发语言_18

  • go进去
  • (P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_后端_19

  • 只有转换成unary_function才会有argument_type
  • (P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器_函数对象_20

  • 参考:从零开始学C++之STL(九):函数适配器bind2nd 、mem_fun_ref 源码分析、函数适配器应用举例