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

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;
}
  • 测试:
    在这里插入图片描述

  • 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;
}
  • 测试:
    在这里插入图片描述

  • 断点:

                     bind2nd(modulus< int>(),  2)) << endl;

返回值是一元函数对象
在这里插入图片描述
F11,看下构造函数,第一个参数是二元函数对象,第二个参数是要绑定的值
在这里插入图片描述
为什么说binder2nd是一元函数对象?
因为他继承至unary_function
在这里插入图片描述
重载()运算符,只接受一个参数说明他是一元函数对象
在这里插入图片描述

  • eg:P83\03.cpp

  • 测试:
    在这里插入图片描述

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的成员函数,
在这里插入图片描述
F11,_Pm表示将Person::Print的成员函数传递进来
在这里插入图片描述
F11,说明mem_fun_ref是一元函数对象。
调用构造函数发现,他将成员函数的地址保存到_Pmemfun。
重载了调用运算符(),_Left表示Person对象,然后调用他的成员函数
在这里插入图片描述

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

都是模板,构成重载
在这里插入图片描述
这是一个二元的函数对象,_Left传递进来的是一个类对象,_Right传递进来的是一个参数
在这里插入图片描述

  • 区别在于是对象还是对象指针
    在这里插入图片描述
  • 断点:
for_each(v.begin(), v.end(), mem_fun(&Person::Print));

将不带参数的成员函数转换成一元函数对象
在这里插入图片描述
F11,通过指针来调用成员函数
在这里插入图片描述

  • 测试:
    在这里插入图片描述

  • 对一般函数的函数适配器
    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;
}
  • 测试:
    在这里插入图片描述

  • 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;
}

4.std::find用法

find() 函数本质上是一个模板函数,用于在指定范围内查找和目标元素值相等的第一个元素。

如下为 find() 函数的语法格式:

InputIterator find (InputIterator first, InputIterator last, const T& val);

其中,first 和 last 为输入迭代器,[first, last) 用于指定该函数的查找范围;val 为要查找的目标元素。

正因为 first 和 last 的类型为输入迭代器,因此该函数适用于所有的序列式容器。

另外,该函数会返回一个输入迭代器,当 find() 函数查找成功时,其指向的是在 [first, last) 区域内查找到的第一个目标元素;如果查找失败,则该迭代器的指向和 last 相同。

值得一提的是,find() 函数的底层实现,其实就是用运算符将 val 和 [first, last) 区域内的元素逐个进行比对。这也就意味着,[first, last) 区域内的元素必须支持运算符。

eg:

  • 可以看到,find() 函数除了可以作用于序列式容器,还可以作用于普通数组。
#include <iostream>     // std::cout
#include <algorithm>    // std::find
#include <vector>       // std::vector
using namespace std;
int main() {
    //find() 函数作用于普通数组
    char stl[] ="http://c.biancheng.net/stl/";
    //调用 find() 查找第一个字符 'c'
    char * p = find(stl, stl + strlen(stl), 'c');
    //判断是否查找成功
    if (p != stl + strlen(stl)) {
        cout << p << endl;
    }
    //find() 函数作用于容器
    std::vector<int> myvector{ 10,20,30,40,50 };
    std::vector<int>::iterator it;

    it = find(myvector.begin(), myvector.end(), 30);
    if (it != myvector.end())
        cout << "查找成功:" << *it;
    else
        cout << "查找失败";
    return 0;
}

参考:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢打篮球的普通人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值