概述
名字空间
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),双向迭代器(bidirectional 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;