您的位置:首页 > 编程语言 > C语言/C++

C++模板编程及函数对象

2007-03-06 15:26 513 查看

概述

名字空间

C++引入namespace关键字用来解决命名冲突这个问题,一个namespace就是一个作用域(scope)。C++标准库中所有的标识符都在std名字空间下,有三种方法使用这些标识符:

直接指定:

std::cout<<”Hello, world!”;

使用using声明:

#include <iostream>

using std::cout;

……

cout<<”Hello, world!”;

……

使用using指令:

#include <iostream>

using namespace std;

……

cout<<”Hello, world!”;

……

 

标准容器

C++标准模板库提供了一些从用数据结构的容器,具体如下:
vector:一个类似动态数组的容器。
 

deque:和vector类似,接口基本相同,唯一不同的是deque的动态数据是两端开放,提供push_front和pop_front接口。
 

List:双向链表容器。
 

set和multiset:这两个容器中的元素会自动按指定的规则排序。set不允许出现重复的元素,而multiset可以。
 

map和multimap:这两个容器中的元素按key/value对结构组织,以key来排序。map类似set,不允许出现key相同的元素,multimap可以。
 

其他:
basic_string:字符串模板类,为两个习惯应用定义了两个typedef:
typedef basic_string<char> string;

typedef basic_wstring<wchar_t> wstring;

 

迭代器

类似于指针。是指向其他对象的对象。对于泛型算法来讲,迭代器扮演着重要的角色。通过迭代器,可以把容器和泛型算法分离出来。
 

迭代器的种类

迭代器分为输入迭代器(input iterators),输出迭代器(output iterators),前向迭代器(forward iterators),双向迭代器(bidirectiona
4000
l iterators)和随机访问迭代器(random access iterators)。
input iterators:只读,向C指针一样,可以比较;可以拷贝和赋值;可以使用操作符++p或p++(向前移动指针)。

output iterators:只写,如同input iterators,可以拷贝和赋值;可以给output iterators写入值,如*p = x;可以使用操作符++p或p++。
 

forward iterators:从概念上讲,forward iterators可以运用于replace之类的算法,即可读也可写。
 

bidirectional iterator:可以使用操作符--p。
 

random access iterators:随机访问迭代器有C指针的所有功能。比如:p+5,p-3。
 

迭代器特性

template <class Iterator>
struct iterator_traits {
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type          value_type;
typedef typename Iterator::difference_type   difference_type;
typedef typename Iterator::pointer               pointer;
typedef typename Iterator::reference           reference;
};
 

在标准算法中会更具iterator_traits来决定针对特定迭代的算法实现,具体在标准算法部分再讨论。
 

当你定义一个新的迭代器类型时,你需要同事定义五个类型:iterator_category, value_type, difference_type, pointer和reference,这五个类型应该是iterator类的嵌套类型。STL已经包含一个辅助类来作为iterator的基类,可以简化新iterator类型的定义:
template <class Category, class Value, class Distance = ptrdiff_t,
          class Pointer = Value*, class Reference = Value&>
struct iterator {
typedef Category          iterator_category;
typedef Value               value_type;
typedef Distance           difference_type;
typedef Pointer             pointer;
typedef Reference         reference;
};
 

标准算法

STL提供了许多常用的算法,这些算法都在<algorithm>头文件中定义,这里主要讲讲如何使一个泛型算法应用到不同的迭代器上。
比如一个advance算法,这个算法使迭代器向前移动指定的距离,通常的做法是为不同的迭代器定义不同的实现版本,如:
template <class InputIterator, class Distance>

void advance_II(InputIterator& i, Distance n)

{

      for ( ; n > 0; --n, ++i) {}

}

 

template <class BidirectionalIterator, class Distance>

void advance_BI(BidirectionalIterator& i, Distance n)

{

      if (n >= 0)

            for ( ; n > 0; --n, ++i) {}

      else

            for ( ; n < 0; ++n, --i) {}

}

 

template <class RandomAccessIterator, class Distance>

void advance_RAI(RandomAccessIterator& i, Distance n)

{

      if (n >= 0)

            for ( ; n > 0; --n, ++i) {}

      else

            for ( ; n < 0; ++n, --i) {}

}

 

然后在定一个外部接口:
template <class InputIterator, class Distance>

void advance_II(InputIterator& i, Distance n)

{

      if (is_random_access_iterator(i))

            advance_RAI(i, n);

      else if (is_bidirectional_iterator(i))

            advance_BI(i, n);

      else

            advance_II(i, n);

}

 

但是,现在结合iterator_traits,我们可以这样:

template <class InputIterator, class Distance>

void advance(InputIterator& i, Distance n, input_iterator_tag)

{

      //implementation

}

 

template <class BidirectionalIterator, class Distance>

void advance(BidirectionalIterator& i, Distance n, forward_iterator_tag)

{

      //implementation

}

 

template <class RandomAccessIterator, class Distance>

void advance(RandomAccessIterator& i, Distance n, random_access_iterator_tag)

{

      //implementation

}

 

template <class InputIter, class Distance>

void advance_RAI(InputIter& i, Distance n)

{

      advance(i, n, iterator_traits<InputIter>::iterator_category());

}

 

STL定义了五个tag类型:

struct input_iterator_tag {};

struct output_iterator_tag {};

struct forward_iterator_tag: public input_iterator_tag {};

struct bidirectional_iterator_tag: public forward_iterator_tag {};

struct random_access_iterator_tag: public bidirectional_iterator_tag {};

 

函数对象

一个函数对象,就是一个包含operator ()运算符重载的对象。如:
FunctionObjectType fo;
fo(…);
 

许多标准算法提过了一个额外的参数,有些标准容器也可以接收额外的模板参数。如查找一个序列是否在是另一个序列的子序列的算法:
template<class ForwardIterator1, class ForwardIterator2>

   ForwardIterator1 search(

      ForwardIterator1 _First1,

      ForwardIterator1 _Last1,

      ForwardIterator2 _First2,

      ForwardIterator2 _Last2

   );

template<class ForwardIterator1, class ForwardIterator2, class Pr>

   ForwardIterator1 search(

      ForwardIterator1 _First1,

      ForwardIterator1 _Last1,

      ForwardIterator2 _First2,

      ForwardIterator2 _Last2

      BinaryPredicate _Comp

   );

第一个search版本只是用普通的==比较来进行查找,而第二个版本可以指定一个函数对象。

我们可以定义一个函数:

bool NoCase(char left, char right)

{

      return toupper(left) == toupper(right);

}

 

然后调用search算法:

string str(“abcdDEfG”);

string subStr(“Ddef”);

string::const_iterator iter = search(str.begin(), str.end(), subStr.begin(), subStr.end(), NoCase);

 

在看一个例子:

class NoCaseCompare

{

public:

      bool operator () (char left, char right)

      {

            return toupper(left) < toupper(right);

      }

};

 

set<string, NoCaseCompare> strSet;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息