配接器
实际上是一种设计模式:一个class接口转换为另一个class因为接口不兼容而无法合作的接口classes,可一起操作。
container adapters
用于修改容器接口的配接器称为container adapter。
stl两个容器queue和stack,其实都只不过是一种配接器。
iterator adapters
应用于迭代器体的配接器称为iterator adapters。包括、和
insert iterators
1.迭代器的类型是output_iterator_tag,输出迭代器。
2.每一个insert iterators内部维护有容器back_insert_iterator为例:
template <class Container> class back_insert_iterator {
protected: Container* container; ... } 该容器可由结构函数指定:
explicit back_insert_iterator(Container& x) : container(&x) {
} 函数back_inserter事实上,这个结构函数也被调用,返回到一个back_insert_iterator对象。
3.重载了=符号实际上会调用插入迭代器进行赋值操作Container的插入操作(push_back、push_front、insert)。比如对于back_insert_iterator:
operator= (const typename Container::value_type& value) {
container->push_back(value); return *this; } 4.*、 、 (int)等符号也重载,但都是。
5.insert_iterator常常用于copy例如,这样使用函数:
copy(ia 1, ia 3, front_inserter(vec)); 事实上,它将继续正确vec容器使用push_front操作,插入前输入迭代器的内容。
3和4中对=符号和*由于符号的重载共同实现了这一功能。copy有:
*result = *first; 当这里的result当插入迭代器时,由4可知*result其实得到的还是result,于是变成了
result = *first; 所以会调用insert iterator的oprator=()函数,进行插入操作。
5.对于insert_iterator类型,它有两个数据成员,除了container外,还保存一个指向容器的普通迭代器iter。因为在实现普通的插入操作时,还需要提供一个插入位置,这个iter就起这样的作用。 它的构造函数以及inserter函数都接收两个参数。
reverse iterators
1.reverse iterators的内部有一个数据成员current,是普通迭代器。它的构造函数就将普通迭代器作为参数。base()函数可以返回这个current。
2.reverse iterators的5种型别和current所属于的类别一样。
3.stl容器中,有正向迭代器的一般也有逆向迭代器(除了forward_list,没有逆向迭代器)。
typedef reverse_iterator<iterator> reverse_iterator;
reverse_iterator rbegin() {
return reverse_iterator(end()); }
reverse_iterator rend() {
return reverse_iterator(begin()); }
...
可以看到,。
3.重载*函数:
reference operator*() const {
Iterator tmp = current;
return *--tmp;
}
也就是说,对reverse iterator解引用的时候,获得的是current的前一个迭代器(减1得到的)的值。
这也正好和容器的rbegin()以及rend()的规定匹配上了,rbegin()解引用取的是end()前一个迭代器的值,永远不会解引用end();而由于永远不会对rend()解引用,所以也永远不会对begin()进行--操作。不会出现问题。
4.reverse iterators的前进(++)操作,就是对current执行后退操作,reverse iterators的后退(--)操作,就是对current执行前进操作。
类似于前进n步和后退n步的操作,都是这样逆向的操作的。
stream iterator
1.将迭代器绑定在一个stream对象上,绑定在istream上的叫做istream_iterator,绑定到ostream上的叫做ostream_iterator。
2.istream_iterator迭代器类型是,ostream_iterator迭代器类型是
3.的实现:
有三个数据成员。一个是指向istream对象的指针,一个是value,还有一个bool变量指明是否读到了eof。
有一个成员函数read(),这个函数实际上就是通过<<符号从stream对象中将一个值输入给value。
有两个构造函数。默认构造函数绑定cin对象,并且将bool变量赋值为false。另一个构造函数接收一个istream对象,并且要,于是value会被赋值(或者会被阻塞)。
解引用操作,就是直接返回value。
++操作,就是调用一次read(),让输入流再输入一个值给value。
ostream_iterator的实现和istream_iterator类似。
4.的实现:
有两个数据成员,一个是指向ostream对象的指针,一个是一个const char*类型的变量,名字叫做string。这个string的作用是作为间隔符。
有两个构造函数,一个只接受ostream对象,另一个还接受一个const char*类型变量。比如:
ostream_iterator<int> outiter(cout, ' ');
这个迭代器将数据输出到cout,每次间隔一个空格。
重载赋值操作=,调用它时,实际上是将value输出到ostream对象,并且如果间隔符号不为空,还要输出一个间隔符号。
*、++等操作都什么也不做,直接返回*this
5.copy操作的实现。
比如outite是一个ostream_iterator,它会被当做copy函数的第三个迭代器参数,也就是result参数。
在拷贝的过程中,会不断做这样的事情:
*result = *first;
对result解引用会直接返回result,于是实际上是result = *first。调用赋值函数operator=,于是就将value输出到ostream对象中。
在迭代的过程中,会不断对result进行++操作,而它也直接返回result。
function adapters
1.container adapters在内部存一个容器,iterator adapters在内部存一个普通迭代器,同理,function adapters也在内部存仿函数的实例化对象。
2.以用于函数合成的compose1为例。
template <class Operation1, class Operation2>
class unary_compose
: public unary_function<typename Operation2::argument_type,
typename Operation1::result_type> {
...
}
将两个模板参数Operation1和Operation2,分别代表两个一元仿函数类型。 类继承一元仿函数unary_function。它的输入类型是Operation2的输入类型,输出类型是Operation1的输出类型。
protected:
Operation1 op1;
Operation2 op2;
public:
unary_compose(const Operation1& x, const Operation2& y)
: op1(x), op2(y) {
}
两个数据成员分别是Operation1类型的对象和Operation2类型的对象。构造函数也是接受两个对象来分别初始化op1和op2。
typename Operation1::result_type
operator() (const typename Operation2::argument_type& x) const {
return op1(op2(x));
}
仿函数经典操作,重载()符号,能看到参数类型是Operation2的参数类型,返回类型是Operation1的参数类型。而重载函数的实际过程也是,先计算op2(x),再将它的结果用op1计算,返回。
3.几种标准库内置的仿函数配接器:
-
not1、not2:对返回值进行逻辑否定。一个处理一元仿函数,一个处理二元仿函数。 -
bind1st、bind2nd:把二元仿函数处理成一元仿函数。它的构造函数会接受一个value参数,value绑定到二元仿函数的其中一个参数上,于是这个二元仿函数之后就只需要接受一个参数,表现得就像是一个一元仿函数。 -
compose1、compose2:一个仿函数的结果作为另一个仿函数的输入,第二个仿函数的输出作为最终的输出。 -
ptr_fun:实现将函数指针当做仿函数来使用。将函数指针作为数据成员,重载的()实际上就是直接调用函数指针。 注意函数指针的定义方式是:函数返回值类型 (* 指针变量名) (函数参数列表);,比如书上所写的Result (*ptr) (Arg)。 -
mem_fun、num_fun_ref:这两个配接器实现将成员函数当做仿函数来使用。它们都存一个类的成员函数的指针,构造函数都接受一个指针。两者的区别在于,前者重载的()函数接受指针类型作为参数,而后者接受引用类型。S (T::*pf) (A),T是这个成员函数属于的类,S是这个成员函数的返回值类型,A是这个成员函数的参数类型(或者为空,表示不接受参数),pf就是这个指针。 通过指针调用成员函数时,方法是return (p->*f)(x);先对函数指针f解引用,然后通过指针p调用这个函数。 通过引用调用成员函数时,方法是return (p.*f(x));,先对函数指针f解引用,然后通过引用类型p调用这个函数。 通过使用这两个配接器,可以在泛型算法中使用类的成员函数作为方法。