在c++编程思想的第二卷中介绍了很多更深入的c++特性,这是现代C++编程的精髓
模板
1.一般类的声明和定义都在H和CPP两种文件中,主要是怕连接时的多重定义,但是对于模板可以放心的将他们都放在H文件中,因为template后面的东西编译器不会为其分配空间,知道有一个模板实例告知。如果不适用内敛的方式,在每次定义模板的函数前都要声明template,而且声明中的类名后面要加<参数>
2.可以这样定义模板类
template<class T,classu…>
template<class T,int size…>
template<class T,int size=100…>//一个默认值
定义函数模板
template<class T,classu…> void f();
template<typename T…> void f();
在使用函数模板时通产个可以省略模板参数(在可以推断出来的时候)
可以这样定义成员函数模板:在类的内部,定义一个函数template<class T,classu…> void f();这个甚至可以是构造函数。
3关键字typename:表示他限定的那个词是一个类型(类内的)而不是一个成员:typename Seq<T>::iterator it;如果不加这个关键字,那么编译器会认为iterator是成员,有语法错误,加上后表示这是一个类型,而it是一个变量。同样template关键字也只能用在模板类中,这个关键字表示他后面出现的那个<为模板参数列表符而不是小于号。
4.模板的特化
全特化:
template <class Window, class Controller>
class Widget
{
... generic implementation ...
};
template <>
class Widget<ModalDialog, MyController>
{
... specialized implementation ...
};
其中 ModalDialog 和 MyController 时定义好的classes,在这里当你构建Widget<ModalDialog, MyController>实例时,将用下面的构造函数,而其他的用上面的,上面的称泛化,下面的叫特化
偏特化:就是部分参数特化,部分泛化
template <class Window> // Window
class Widget<Window, MyController> // MyController
{
... partially specialized implementation ...
};
这里window是范化的,MyController是特化的,也就是构造一个任意类和MyController的实例时调用这个构造函数
这个构造可以很复杂,泛化的类可以也是一个模板类
template <class ButtonArg>
class Widget<Button<ButtonArg>, MyController>
{
... further specialized implementation ...
};
5.局部类:
也就是定义在函数中的类,这个类不能定义static成员变量,也不能存取non-static的局部变量
void Fun()
{
class Local
{
... member variables ...
... member function definitions ...
};
... code using Local ...
}
函数不能偏特化
异常处理
1.捕获所有异常使用catch(...)
2重新像更高一级跑出异常要在catch子句中写一个throw
3、不捕获异常,如果异常没有被任意一个层次捕捉到,那么就睡直接调用程序中的terminate函数,它的默认实现是abort(),这不是一个正常终止程序的方式,全局变量不被析构
可以使用set_terminate来设置自己的terminate函数。
4、标准异常类:exception,他有很多派生类提供各种异常,可以查阅
5异常规格说明:void f();可能跑出各种异常void f() throw(a,b..);理论上只抛出这些异常;void f()throw();理论上不抛出任何异常;
如果程序抛出了不在描述中的异常,那么会调用unexpected()函数,默认下这个函数执行terminate函数,可以使用set_unexpected()来重新设置这个函数。
函数对象:
他是实现了重载()的类的一个实例。
在stl的算法中,这个类的实例通常被用来作为判定函数,它并不是函数,但是因为他重载了(),可以调用a(),类似于一个函数,所以叫做函数对象,它比简单的判定函数的好处在于它是一个类的对象,它里面可以存储更多的信息
在通用算法中,算法有几元,它的判定函数就必须使用几元,算法的元是指它传递到判定函数中的参数的个数。
STL算法:
1、填充和生成:fill() fill_n() generate()
2、计数:count() count_if()
3、操作序列: copy() copy_backward() reserve()[倒置] reserve_copy()[倒置后复制它出] rotate()【交换位置】rotate_copyright()
next/preve_permutation()[数学上的排列组合] rondom_shuffle()【随机重排】 partition()[划分,将满足某个条件的元素移到开头]
4、查找和替换: find/findif()[线性查找] adjacent_find()[查找两个临近的相等元素] find_first_of()[在第二个序列上查找与第一个序列上某个元素相等的元素]
search()[查找第二个序列是否出现在第一个序列中(次序也一致)] find_end()[同serch,但是返回最后出现的那一段位置]
search_n()[查找一组相邻的同样的值] min/max_element()[找到最小/大的那个值首次出现的位置] replace()replace_if()replace_copy_if()[找到后替换]
5、比较范围:equal()【两个范围是否元素相同顺序相同】lexicographical_compare()[比较两个范围的字典编纂顺序]
6、删除元素:remove() remove_if() remove_copy_if()
unique()[删除相邻的同样的元素(相邻的值留下一个),通常之前先用sort(),这样可以每个元素都只有一个]
7、排序合并:sort()[按升序排序] stable_sort()[按升序排序并保持相等元素的顺序] partitial_sort()【部分排序】nth_element()[保证其中一个元素作为划分点,左侧小于它,右侧大于他,用
于算中值和百分点] binary_serach()[在已排序的范围内寻找] upper_bound()[在一个范围内找出大于一个值的元素最后出现的那个位置]
equal_range()【找到在一个范围内某只出现的范围】merge() inplace_merge()[合并]
在已拍好序的集合上的集合运算
include()【是否包含】set_union/differrence/intersection/symmetric_difference()
8、堆运算:通常可以将一个序列转化成一种类似于对的结构,在这里面便于一次找出优先权最高的元素
make_heap()[将序列转化成堆]push_heap() pop_heap()[将堆顶的元素一道序列的最尾断,不是移除]sort_heap()【将一个堆序的序列重新变成一个按顺序排列的序列】
9、对一个范围的成员全部应用某种运算;foreach()【对每个成员使用某个函数】transforma()【对每个成员使用某个函数并把结果写入一个序列】
10、数值算法:accumulate()【对所有元素循环的调用一个函数得到一个累计的值】inner_product()【内积】partitial_sum()adjacent_diffrence()[得到原数列相邻元素的差]
11、其他:pair():一个封装两个对象的类,通过make_pair()构造
distance():返回两个迭代器之间的距离,增加次数
back_inserter/inserter/front_inseeter():为一个容器构建一个迭代器,这个迭代器只用于在某个位置进行插入
min() max() [比较] swap()[值交换]
容器:
容期间可以通过assign进行互相的转换
vector:它可以快速的访问,但支不持在中间插入,它溢出时的代价很高,因为先要分配更大的存储空间,然后把原先的内容拷贝过来。可以使用reserved告知预先要多大的空间,而使一个整数作为它的构造函数的第一个参数的做法则是把所有的成员默认初始化。
使用vector的最有效的方法是,在开始使用reserved告诉预先需要的空间大小,然后只在序列后端插入或删除元素
deque:在不确定对象数量时尽量用它而不用vector,因为它在两端插入或删除的效率更高。但是随机访问不如vector。它不支持中间插入。
list:在任意地方插入删除,但是不支持随机访问,只能遍历,遍历效率也较慢。如果是较大较多的对象,尤其是构造很麻烦的对象,尽量使用它,如果要进行排序等更是的,因为在list中这通常只需要改变指针的指向而已。
适配器:stack、queue、prioruty_queue为适配器,他们是用vector、list和dequeue来实现的,每一个适配器都可以用它们分别实现。它们的默认方式通常被认为是最好的。
prioruty_queue:出于安全,它没有设计迭代器,但是可以使用mack_heap等操作讲vector模拟成优先队列。
关联式容器:set/multyset/map/multymap都是,它们的特点是将一个值关联一个关键字,set可看成只有关键字。
set:存放唯一的且排过序的成员。
表示二进制位:
c中没有表示二进制数值的方法,只有十进制和十六进制,有两个方法可以代替。
bitset类:它表示有固定位数的二进制串。
vector<bool>容器
valarray容器,他可以操纵一组数组,然后进行各种数值运算,可以对其中的一部分切片出来分析。