(P83)stl(十一):适配器,函数适配器,针对成员函数的函数适配器
原创
©著作权归作者所有:来自51CTO博客作者喜欢打篮球的普通人的原创作品,请联系作者获取转载授权,否则将追究法律责任
文章目录
- 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;
}
- 测试:
- 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;
}
- 测试:
- go进去
- 只有转换成unary_function才会有argument_type
- 参考:从零开始学C++之STL(九):函数适配器bind2nd 、mem_fun_ref 源码分析、函数适配器应用举例