目录
4 OOP(Object-Oriented programming)与GP(Generic Programming)
4.1 OOP(面向对象编程)企图将datas和methods关联在一起
4.2 GP(泛型编程)是将datas和methods分开来
5.2.3 模板偏特化(特化与偏特化(局部特化 Partial Specialization))
1 你应该具备的基础
1.1 你应该具备的基础
- C++基本语法(包括如何正确使用模板,templates)
1.2 我们的目标
-
使用C++标椎库
-
深入认识C++标准库(胸中自有丘壑)
-
良好使用C++标准库
-
扩充C++标准库
2 标准库介绍
-
C++标准库:C++ Standard Library
-
C++标准模板库:Standard Template Library(STL)
2.1 C++标准库与C++标准模板库二者关系及表现形式
-
标准库是由编译器提供的(比如我们常见的VC,GCC...),STL 属于标准库的一部分(占比绝大部分85%左右),标准库一定是包含(大于)STL的;
-
标准库引用形式:
-
C++标准库都是以头文件的形式提供不带.h,比如:#include<vector>;
-
新式C语言的头文件不带.h,一般是:#include<cstdio>;
-
命令空间:namespace std;
-
- 标准库引用方法:
#include <iostream>
#include <cstdio> //snprintf()
#include <cstdlib> //RAND_MAX
#include <cstring> //strlen(), memcpy()
#include <string>
using namespace std;
using std::cin;
using std::cout;
using std::string;
2.2 STL六大部件
STL六大部件解释如下:
-
容器:容器就是我们存放数据的地方,相当于数据仓库,实现方式是类模板;
-
分配器:管理容器背后的内存使用,实现方式是类模板;
-
算法:常见的比如排序、查找等,实现方式是函数模板;
-
迭代器:算法操作容器的桥梁,是一种泛化的指针,实现方式是类模板;
-
仿函数:或者叫Function Object(函数对象),它是一个类对象,其次它重载了
()
操作符,使用在自定义类对象时,比如我们对石头进行排序,在算法操作时就可以写一些仿函数供算法正确使用,实现方式时类模板; -
适配器:相对于迭代器、仿函数、容器的数据转换,实现方式是类模板。statck和queue也被称为容器适配器。
2.3 STL的简单使用
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
int main()
{
int ia[6] = {1, 2, 3, 4, 5, 6};
vector<int, allocator<int>> vi(ia, ia + 6);
cout << count_if(vi.begin(), vi.end(),
not1(bind2nd(less<int>(), 3)));
//not1是一个function adapter(negator)
//bind2nd是一个function adapter(binder)
//less<int>()是一个function object(是个临时对象)
//not1(bind2nd(less<int>(), 3)));是一个predicate(判断式)
return 0;
}
2.4 时间复杂度
要讨论时间复杂度,其中n必须建立在足够大的工业数据基础上。
算法复杂度:大O表示法
2.5 STL中的区间表示法
STL采用前闭后开区间表示数据的范围,所有的数据都是通过begin()和end()两个函数表示数据的范围,begin表示数据的头,end表示数据尾的下一个元素,也就是说,对end进行解引用操作得到的指针它是不确定的东西,也可能造成程序宕机或者其他不是你心里所想的东西。
3 标准库源代码版本介绍
3.1 VC的编译器源码目录
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include
3.2 GNU C++的编译器源码目录
4 OOP(Object-Oriented programming)与GP(Generic Programming)
-
OOP: Object-oriented programming 面向对象的编程 ,例如C++中的类和对象。
-
GP:Generic Programming 泛型编程 ,例如C++中的模板。
4.1 OOP(面向对象编程)企图将datas和methods关联在一起
比如标准库中的list:
template <class T,
class Alloc = alloc>
class list{
......
void sort();
};
我们看到list定义了一个自己的成员函数,那么为什么list不能使用::sort()进行排序呢,我们先来看一下::sort()的源码:
template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last){
if(first != last){
__introsort_loop(first, last, value_type(first), __lg(last - first) * 2);
__final_insertion_sort(first, last);
}
}
template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first,
RandomAccessIterator last,
T*,
Size depth_limit){
......
RandomAccessIterator cut = __unguarded_partition
(first, last, T(__median(*first, *(first + (last - first)/2), *(last - 1))));
......
}
我们发现::sort()支持的迭代器是随机访问迭代器,随机访问迭代器除了可以递增递减之外,还支持类似c.begin() + k的操作,而list中的迭代器不是随机访问迭代器,所以也就不提供这个操作。这样设计是合理的,因为list是链表,无法在线性时间内得到递增或递减k次的结果。
4.2 GP(泛型编程)是将datas和methods分开来
采用GP的好处:
(1)Containers和Algorithms可以分别“闭门造车”,其间以iterator通信即可。
(2)Algorithms通过iterators确定操作范围,并通过iterators取用Container的元素。
比如说vector和deque都提供随机访问迭代器,所以可以使用::sort()进行排序,体现了GP的设计思想。
template <class T,
class Alloc = alloc>
class vector{
......
};
template <class T,
class Alloc = alloc,
size_t BufSiz = 0>
class deque{
......
};
::sort()有两个版本:
template <typename _RandomAccessIterator>
inline void
sort(_RandomAccessIterator __first,
_RandomAccessIterator __last)
{
......
}
template <typename _RandomAccessIterator,
typename _Compare>
inline void
sort(_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Compare __comp)
{
......
}
所有的算法,其内最终涉及元素本身的操作,无非就是比大小。
5 阅读C++标准库源码的必要基础
5.1 操作符重载
这张图总结得很好。注意操作符重载既可以是成员函数,也可以是全局函数。
但是不理解最后一栏,对象后面的一元操作符为啥非要有一个参数?(这个参数没有任何意义,只是为了区分前置和后置版本)
限制条件:哪些操作符不能重载
看一个例子:iterator是一个泛化的指针
template <class T, class Ref, class Ptr>
struct __list_iterator{
typedef __list_iterator<T, Ref, Ptr> self;
typedef bidirectional_iterator_tag iterator_catagory;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __list_node<T>* link_type;
typedef ptrdiff_t difference_type;
link_type node;
// 操作符重载
reference operator*() const { return (*node).data; }
pointer operator->() const { return &(operator*()); }
self& operator++() { node = (link_type)((*node).next); return *this; }
self operator++(int) { self tmp = *this; ++*this; return tmp; }
。。。
};
5.2 模板
5.2.1 类模板
5.2.2 函数模板
编译器对函数模板进行实参推导:
5.2.3 成员模板
5.2.4 模板特化(泛化与特化)
泛化(GP Generic Programming),特化(Specialization),二者区别在于特化版本相比泛化版本可能存在效率上的优化
5.2.3 模板偏特化(特化与偏特化(局部特化 Partial Specialization))
-
特化又叫做全部特化,上面的例子中类模板参数只有一个,其实可以由多个,这个全部特化就是对所有的参数都进行特殊绑定;
-
偏特化叫做局部特化,下面例子对于多个参数只绑定其中一部分(局部数量或者局部范围内的绑定)。部分特化:个数上的偏特化+范围上的偏特化.
//泛化
template <class T,
class Alloc = alloc>
class vector
{
......
};
//个数上的偏特化
template <class Alloc>
class vector<bool, Alloc>
{
......
};
(2) 范围上的偏
//泛化
template <class Iterator>
struct iterator_traits{
typedef typename Iterator::iterator_catagory iterator_catagory;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
};
//partial specialization for regular pointers
template <class T>
struct iterator_traits<T*>{
typedef random_access_iterator_tag iterator_catagory;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
//partial specialization for regular const pointers
template <class T>
struct iterator_traits<const T*>{
typedef random_access_iterator_tag iterator_catagory;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};