有一部分错别字
第一章
1、异常处理是C++的主要特征之一
2、assert():用于开发阶段调试,#define NDEBUG 使得assert()失效。
3、C语言中错误处理信息:1-在函数中返回错误信息。2-使用C库的信号处理系统signal(),raise()。3-使用C库的setjmp()和longjmp().信号处理方法和setjmp、longjmp函数不调用析构函数,对象不能被正确清理。
4、throw 创建程序所抛出对象的一个拷贝。throw表达式返回这个对象。try/catch异常处理器可以处理某种异常类型和这种异常类型的派生类。并且为避免再次拷贝异常对象,最好通过引用而不是通过值来捕获异常。通过引用来捕获异常,基类异常处理器能够捕获派生类异常。
5、catch(...){}可以捕获任何类型的异常。在异常处理器内部catch(){throw;}使用不带参数的throw可以重新抛出异常。
6、如果没有一个异常处理器可以捕获异常,terminate()会自动被调用。
7、防止资源泄漏,采用方式:1-在构造函数中捕获异常,用于释放资源。2-在对象的构造函数中分配资源,并在对象的析构函数中释放资源。
8、若返回类型为引用,则表示不能返回0.因为不能有空引用。
9、RAII,资源获得式初始化,是一个封装类,用于封装指向分配的对内存的指针,使得程序能够自动释放这些内存。auto_ptr类模板在头文件
10、从exception类(定义在头文件
11、异常规格说明:int fun () throw(big,small);函数可能抛出的异常写在throw之后的括号中。int fun()throw()表示函数不会抛出任何异常。int fun()表示函数有可能抛出任何类型的异常。如果异常不在异常规格说明的异常集中,那么unexcepted会被调用。默认的unexpected调用terminate函数。可以使用set_unexpected函数(头文件
12、异常规格说明中包含std::bad_exception 在
13、异常规格说明与继承。派生类的异常说明应该在结构层次上低于基类的异常说明。即基类的异常说明--》派生出派生类的异常说明。异常规格说明是为非模板准备的。
14、operator=应遵守6个模式:1-确保程序不给自己赋值,如果是的话跳6。2-给指针数据成员分配新内存。3-从原有的内存区向新分配的内存区拷贝数据。4-释放原有的内存。5-更新对象状态,也就是把指向分配新堆内存地址的指针赋值给指针数据成员。6-返回*this。
15、当delete对象的时候,对象的析构函数会被调用。不要在析构函数中抛出异常 。
第二章
1、测试套件框架TestSuit,包含两个主要的类:Test和Suit。Test类保存测试成功和失败的次数。可以从Test类派生自己的测试对象。只需要重写成员函数run()即可,并用test_()来测试。使用report函数显示前面的输出。
2、Test类有3个虚函数:虚析构函数、reset函数,纯虚函数run;基类设置虚析构函数,表示可以通过基类指针释放在堆上分配的派生类对象。
3、利用宏处理代码跟踪:这两个宏可以完成调试器的基本功能,跟踪代码执行,并显示表达式的值。
#define TRACE(ARG) cout<<#ARG<
第三章
1、C++字符串string极大减少了C语言编程中3中最常见的错误:1-数组越界。2-通过未被初始化或被赋以错误值的指针来访问数组元素。3-在释放了某一数组原先所分配的存储单元后仍保留了悬挂指针。
2、创建string对象:1-创建空string对象。2-将字符串传给构造函数。3-用string=字符串方式初始化。4-用一个string初始化另一个string。
3、string s2(s1,0,8)从s1[0]开始的8个字符赋值给s2.
4、string s; s.substr(20,10)提取从s[20]开始的10个字符。
5、使用迭代器。string source; string s(source.begin(),source.end());
6、string s(5,'a'),用5个字符'a'初始化s.
7、对字符串操作:string s, 大小:s.size(),s.length(). 当前分配的存储空间的规模:s.capacity()。从s[1]处插入:s.insert(1,"hua");s.insert(8,tag+' ')从末尾追加:s.append("dfd");
替换:s.replace(4,5,"dfdf");从s[4]开始替换5个字符。查找:i=s.find(tag,0)从s[0]开始查找,默认find(tag)从0开始查找。返回size_t,判断查找到末尾:if(i==string::npos)
替换:replaceAll(s,"hua","XXX")将S的所有hua字符串替换为XXX
8、string::replace()一次只替换一次。算法replace(s.begin(),s.end(),'X','Y')将某个字符全部用另一个字符换掉。s=s1+s2.使用operator + 和operator +=
9、字符串查找:find,rfind,find_first_of找第一个与指定数值中任一个字符匹配,find_last_of,find_first_not_of,find_last_not_of
10、toupper,tolower(char),
11、反向查找s.rfind.从后向前查找,不成功返回string::npos
12、从字符串中删除字符:s.erase(0,string::npos),两个默认值,起始位置,删除的个数。s.erase()删除所有。
13、
14、字符串比较string first,string second. first.compare(second)==0,>0.<0, first.compare(1,7,second,1,7),比较first从first[1]开始的7个字符和second[1]开始的7个字符。s[n]和s.at(n)一样,但是s.at(n)可以抛出异常out_of_range()。
15.字符串交换:first.swap(second)
16、文件操作:string fname,删除文件:remove(fname.c_str()),目录存在:if(!exist(fname)).ifstream in(fname.c_str()),if(!in){exit(EXIT_FAILURE);}
第四章
1、#ifndef #define #endif 最主要的目的是防止头文件被重复包含与编译。
2、1-while(fgets(buf,size,fp));2-fputs(buf,stdout);3-while((c=fgetc(fp))!=EOF);4-fputc(c,fp);5-fread(buf,size,count,fp),每个count有size个字符,6-fwrite(buf,size,count,fp);7-while(!feof(fp));8-fflush(fp);9-fseek(fp,offset,fromwhere);formwhere:SEEK_SET:0,SEEK_END:2,SEEK_CUR:1;10-ftell(fp);文件指针相对文件首偏移字节数。
11-rewind(fp);将指针移至文件开头。12-memcpy(newdata,data,sizeof()*count);
3、ostream &os;char fillc=os.fill('0');填充'0',返回先前的填充。os<
4、按行输入:成员函数get(),成员函数getline(),全局函数getline ()。1-2-有三个参数:指向缓冲区的指针、缓冲区大小、结束字符:默认'\n',while(in.get(buf,SZ) in.get(); 第一个get读SZ-1个字符,遇到结束符。用get()跳过输入流中的结束符。或者使用ignore(int N=1,char c=EOF),跳过的字符的数目,默认为1,遇到C字符时,函数退出,默认为EOF。 while(in.getline(buf,SZ)在遇到结束字符的时候,两个都会在结果缓冲区末尾存储一个0,区别:当遇到结束符,get停止执行,不从输入流中提取结束符。再调用get,会遇到同一个结束符,函数将立即返回而不会提取输入。而getline相反,将从输入流中提取结束符,但仍然不会把它存储到结果缓冲区中。get的重载版本:1-int get(),没有参数,返回int类型的下一个字符.2-get(char &),从流中读取一个字符放到这个参数中。3-把流对象存储到基础的缓冲区中。
5、处理流错误:ios::badbit,发生致命错误,流不能继续使用。ios::eofbit,输入结束,ctrl+D. ios::failbit,输入非法数据,流可以继续使用。ios::goodbit:正常。清空标志位:myStream.clear();设置某个标志位,重置另一个标志位:myStream.clear(ios::failbit|ios::eofbit);
6、打开刚创建的文件:ofstream out("file.out");ifstream in("file.out");对同一个文件打开读写要确定关闭文件。方法:一、使用大括号,是对象离开作用域调用析构函数,{out}in.二、使用out.close().
7、文件打开模式:ios::in打开输入文件ios::out打开输出文件ios::app打开一个仅用于追加的输出文件ios::ate打开一个已存在的文件,并将文件指针指向文件末尾ios::trunc如果文件存在,截断旧文件。ios::binary以二进制方式打开文件。回车/换行:0x0D/0x0A
8、流缓冲:streambuf对象将<<右侧对象中的字符输出到左侧的对象中, ifstream in("i.cpp");cout<
10、char readData[STR_NUM][STR_LEN]={{0}};
11、字符串输入输出流iostringstream直接对内存而不是对文件和标准输出设备进行操作。它使用和cin、cout、相同的读取和格式化函数来操纵内存中的数据。写字符到字符串流,使用ostringstream,从这个流读取字符,可以使用istringstream。头文件
string stuff;
getline(cin, stuff); // Get rest of the line
cout<
os << "integer = " << i << endl;
os << "float = " << f << endl;
os << "string = " << stuff << endl;
string result = os.str();
cout << result << endl;
重载版本的os.str("huaguanglu");cout<
13、格式化域:ios::basefield (ios::dec使整型数值的基数为10,ios::hex使整型数值的基数为16,ios::oct使整型数值的基数为8).ios::floatfield(ios::scientific以科学计数的形式显示浮点数.ios::fixed以固定格式显示浮点数。)ios::adjustfield(ios::left使数值左对齐,填充字符右边空位。ios::right,ios::internal填充字符放在正负号和数值之间正负号左对齐,数值右对齐),cout.setf(ios::fixed,ios:floatfield);
14、宽度、填充、精度:int ios::width()返回当前宽度,默认为0,in ios::width(int n)设定宽度,返回先前。,int ios::fill()返回当前填充字符,默认为空格,int ios::fill(int n)设定填充字符,返回先前,int ios::precision()默认精度小数点后面六位,int ios::precision(int n)设定精度,返回先前。宽度不会截断字符。宽度只规定最小长度。
cout.setf(ios::boolalpha)返回true、false,代替0,1
15、操纵算子:刷新流:cout<
showbase,noshowbase,showpos,noshowpos,showpoint,noshowpoint,
uppercase,nouppercase,skipws,noskipws,
left,right,internal,
scientific,fixed,
setiosflags()相当于ios::setf(),resetiosflags,相当于ios::unsetf(),
setbase(base n),n取值8,10,16,输出的基数。setfill(char n)相当于ios::fill(n),
setprecision(int n),setw(int n),
举例:
istringstream is("one 2.34 five");
string temp;
is >> setw(3) >> temp;temp="on".is >> setw(2) >> temp;temp="e".
16、const ulong ULMAX=numeric_limits
17、time_t timer;srand(time(&timer));
第五章
1、模板参数:无类型模板参数template
T data[N];
size_t count;
public:
void push(const T& t);
};
实例化模板时,为参数N提供一个编译时常数Stack
2、默认模板参数:template
template
函数模板不可以使用默认的模板参数。却能使用模板参数作为普通函数的默认参数。
template
template
public:
void push_back(const T& t){}
T* begin(){return data;}
T* end(){return data+count;}
};
template
Seq
public:
void append(const T& t){seq.push_back(t);}
T* begin(){return seq.begin();}
T* end(){rturn seq.end();}
}
main()
{
Container
}
此时的默认参数需要重新声明:
template
template
typename Seq
typename T::id i;
typename作用:
1-typename不是创建一个新类型,而是声明id是一个嵌套类型,然后创建这个类型的对象 i。
class Y{
class id {};
};
创建一个新类型:typedef typename Seq
2-typename代替class
4、
5、min<>(1,4),表示强制使用模板。
1-可以在不包含
transform(s.begin(),s.end(),s.begin(),static_cast
6、模板特化:template<>告诉编译器接下来是模板特化。template<> const char* const&min
7、模板不是代码,是产生代码的指令。防止模板代码膨胀:一个模板化的Stack容器,用int,int *,char*特化,会生成3个版本的Stack代码,可以用void* 进行完全特化,然后从void*实现中派生出所有的其他的指针类型。
8、名称查找问题:编译器第一阶段对模板解析,第二阶段模板实例化。限定名:MyClss::f()/x.f()/p->f() 关联参数查找。若名称是关联的,则它的查找在实例化进行,非限定的关联名称除外,它是一个普通的名称查找,它的查找在定义时进行,比较早。
9、在类中声明一个友元函数,就允许一个类的非成员函数访问这个类的非公有成员。友元函数模板必须提前声明。
template
template
template
public:
friend void f<>(const Friendly
friend void f(const Friendly
};
10、模板元编程:编译时编程,在程序开始运行前就已经完成了计算。
template
enum { val = Factorial
};
template<> struct Factorial<0> {
enum { val = 1 };
};
int main() {
cout << Factorial<12>::val << endl; // 479001600
} ///:~
11、模板定义的源代码与它的声明相分离,使用export关键字。
export
template
enum { val = Factorial
};
第六章
1、copy: int a[SZ];int b[SZ];copy(a,a+SZ,b); equal: equal(a,a+SZ,b);相等返回true.
2、vector
copy(v1.begin(),v1.end(),back_inserter(v3)), back_inserter在头文件
3、取<=15的数:bool gt15(int x){return 15
remove_copy_if(a,a+SZ,ostream_iterator
ofstream out();remove_copy_if(a,a+SZ,ostream_iterator
ifstream in(); remove_copy_if(istream_iterator
istream_iterator
5、size_t n=count_if(a,a+SZ,gt15);产生>15的整数元素的个数。int *p=find(a,a+SZ,20)搜索一个序列,直到遇到等于第三个参数的元素。返回第一次找到的指针位置。
6、函数对象:它实现起来像函数同时保存状态,使用时却不用考虑函数参数的个数。这种抽象叫函数对象。
remove_copy_if(a,a+SZ,b,bind2nd(greater
int a[]={12,20,12};count_if(a,a+SZ,not1(bind1st(equal_to
产生标准函数对象的模板表达式:类型:unary_function和binary_function.
plus
tansform(v.begin(),v.end(),v.begin(),bind2nd(multiplies
7、sort(a,a+SZ),
8、函数指针适配器ptr_fun()把一个指向函数的指针转化成一个函数对象。
int d[] = { 123, 94, 10, 314, 315 };
const int DSZ = sizeof d / sizeof *d;
bool isEven(int x) { return x % 2 == 0; }
int main() {
vector
transform(d, d + DSZ, back_inserter(vb),
not1(ptr_fun(isEven)));
copy(vb.begin(), vb.end(),
ostream_iterator
cout << endl;
// Output: 1 0 0 0 1
} ///:~
9、for_each(v.begin(),v.end(),mem_fun(&shape::draw))算法将序列中每一个元素一次传递给第三个参数指示的函数对象。mem_fun()使用指向成员的一个指针来作为它的参数。mem_fun_ref()为一个对象直接调用成员函数
#include
#include
#include
#include
#include "../purge.h"
using namespace std;
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() {}
};
class Circle : public Shape {
public:
virtual void draw() { cout << "Circle::Draw()" << endl; }
~Circle() { cout << "Circle::~Circle()" << endl; }
};
class Square : public Shape {
public:
virtual void draw() { cout << "Square::Draw()" << endl; }
~Square() { cout << "Square::~Square()" << endl; }
};
int main() {
vector
vs.push_back(new Circle);
vs.push_back(new Square);
for_each(vs.begin(), vs.end(), mem_fun(&Shape::draw));
purge(vs);
} ///:~
class Angle {
int degrees;
public:
Angle(int deg) : degrees(deg) {}
int mul(int times) { return degrees *= times; }
};
transform()要求它调用的函数返回一个值。不能使用transform()调用返回值为void的成员函数,也不能调用只有一个参数的for_each函数
int main() {
vector
for(int i = 0; i < 50; i += 10)
va.push_back(Angle(i));
int x[] = { 1, 2, 3, 4, 5 };
transform(va.begin(), va.end(), x,
ostream_iterator
mem_fun_ref(&Angle::mul));
cout << endl;
// Output: 0 20 60 120 200
} ///:~
vector
vector
it=find_if(v.begin(),v.end(),mem_fun_ref(&string::empty));
10、string-->char *-->atof
transform(v.begin(),v.end(),back_inserter(b),mem_fun_ref(&string::c_str));
transform(b.begin(),b.end(),back_inserter(c),std::atof);
11、填充和生成: vector
fill(v1.begin(),v1.end(),"ddd"); fill_n(back_inserter(v2),7,"bye"); fill_n (first,n,value)对由first开始的n个元素赋值value。
generate(v1.begin(),v1.end,gen()); 对区间每个元素调用gen(). generate_n(back_inserter(v2),7,gen())对gen()调用7次,将返回值赋给由first开始的7个元素。
12、计数:count(v.begin(),v.end(), value); count_if(v.begin(),v.end(),pred)//pred返回true的个数
13、操作序列:
copy(v.begin(),v.end(),dest.begin())
copy_backward(v.begin(),v.end(),dest.begin())//以相反的顺序复制元素
reverse(v.begin(),v.end())//倒置原序列范围的元素
reverse_copy(v.begin(),v.end(),dest.begin())
swap_ranges(v.begin().v.end(),v2.begin())//交换相等大小两个范围的内容
rotate(first,middle,last)//[first,middle)内容移至末尾,[middle,last)元素移至开始
rotate_copy(first,middle,last,dest)
next_permutation(first,last)//排列成后继的排列
next_permutation(first,last,pred)//重载
pre_permutation(first,last)//排列成前驱的排列
pre_permutation(first,last,pred)//重载
random_shuffle(first,last)//随机重排范围内的元素
random_shuffle(first,last,rand)//重载,使用用户提供的随机函数重排
partition(first,last,pred)//划分
stable_partition(first,last,pred)
14、查找和替换:
find(first,last,value)
find_if(first,last,pred)//pred==true 返回
adjacent_find(first,last)//两个邻近相等
adjacent_find(first,last,pred)//查找相邻两个符合pred的元素
find_first_of(first1,last1,first2,last2)
find_first_of(first1,last1,first2,last2,pred)
search(first1,last1,first2,last2)//第二序列是否出现在第一序列范围之内,顺序完全一致,返回首先出现的位置
search(first1,last1,first2,last2,pred)//比较的每对元素是否使pred为true.
find_end(first1,last1,first2,last2)//第二序列是否是第一序列的子集,返回最后出现的位置
find_end(first1,last1,first2,last2,pred)//比较的每对元素是否使pred为true.返回最后出现的位置
search_n(first,last,value)//找count个连续的值,与value相等。
search_n(first,last,value,pred)//与value相等的值传递给pred,返回true,否则返回last.
min_element(first,last)//最小值首次出现的位置
min_element(first,last,pred)//返回r,对(first,r)范围中的元素使pred(*e,*r)都为假。
replace(first,last,old_value,new_value);
replace_if(first,last,pred,new_value);
replace_copy(first,last,result,old_value,new_value);
replace_copy_if(first,last,result,pred,new_value);
15、比较范围:
equal(first1,last1,first2)
equal(first1,last1,first2,pred)
lexicographical_compare(first1,last1,first2,last2)//范围1序列元素小于范围2序列元素
lexicographical_compare(first1,last1,first2,last2,pred)
pair
mismatch(first1,last1,first2)//比较两个序列从哪儿开始不同,将两个位置装入pair返回,用first,second访问元素。
mismatch(first1,last1,first2,pred)//比较两个序列从哪儿开始不同,将两个位置装入pair返回,用first,second访问元素。
16、删除元素:
remove(first,last,value)//返回new_last
remove_if(first,last,pred)//返回new_last
remove_copy(first,last,result,value)//返回new_last
remove_if(first,last,result,pred)//返回new_last
真正删除:c.erase(remove(c.begin(),c.end(),value),c.end);
unique(first,last)//删除相邻的相等值的副本,使用unique前,需要先sort().
unique(first,last,pred)
unique_copy(first,last,result)
unique_copy(first,last,result,pred)
17、排序和运算
排序:
sort(first,last)//升序
sort(first,last,pred)
stablesort(first,last)//升序,保持相等元素的原始顺序
stablesort(first,last,pred)
partial_sort(first,middle,last)//对一定数量元素排序,放入[first,middle)中,范围[middle,last)元素不保证有序
partial_sort(first,middle,last,pred)
partial_sort_copy(first1,last1,first2,last2)
partial_sort_copy(first1,last1,first2,last2,pred)
nth_element(first,nth,last)//也是对一部分处理,[first,nth)元素满足 operator <,而[nth,last)都不满足。
nth_element(first,nth,last,pred)
运算:
在已排序的序列中查找
binary_search(first,last,value)
binary_search(first,last,value,pred)
lower_bound(first,last,value)//第一次出现的位置,若没有,返回应该出现的位置
lower_bound(first,last,value,pred)
upper_bound(first,last,value)//超过value最后出现的位一个置,若没有,返回应该出现的位置
upper_bound(first,last,value,pred)
pair
equal_range(first,last,value)//结合了lower_bound和upper_bound,返回一个指出value在已排序的范围[first,last)中首次出现和超越最后出现的pair,如果没有找到,这两个迭代器都指 //出value在该序列中应该出现的位置。
equal_range(first,last,value,pred)
合并已排序的序列
merge(first1,last1,first2,last2,result)
merge(first1,last1,first2,last2,result,pred)
inplace_merge(first,middle,last)//[first,middle)有序,[middle,last)有序,两个合起来
inplace_merge(first,middle,last,pred)
在已排序的序列上进行集合运算
includes(first1,last1,first2,last2)//序列2是1的子集,返回true
includes(first1,last1,first2,last2,pred)//序列2是1的子集,返回true
set_union(first1,last1,first2,last2,result)//求并集,返回result.end().
set_union(first1,last1,first2,last2,result,pred)
set_intersection(first1,last1,first2,last2,result)//求交集,返回result.end().
set_intersection(first1,last1,first2,last2,result,pred)
set_difference(first1,last1,first2,last2,result)//求集合的差,返回result.end().
set_difference(first1,last1,first2,last2,result,pred)
set_symmetric_difference(first1,last1,first2,last2,result)//求在集合1不在集合2,在集合2不在集合1,返回result.end().
set_symmetric_difference(first1,last1,first2,last2,result,pred)
18、堆运算
make_heap(first,last)//建堆
make_heap(first,last,pred)
push_heap(first,last)//向范围[first,last-1)堆中增加元素*(last-1)
push_heap(first,last,pred)
pop_heap(first,last)//将最大的元素 *first 放入位置*(last-1)并且重新组织剩余的范围。
pop_heap(first,last,pred)
sort_heap(first,last)//转化成普通的排列顺序,是不稳定的排序
sort_heap(first,last,pred)
19、对某一范围内的所有元素进行运算
UnaryFuntion for_each(first,last,UnaryFuntion f);//对范围中每个元素应用f,最终返回值是f
OutIterator transform(first,last,OutIterator result,UnaryFunction f)//f(*first),返回result.end()
OutIterator transform(first,last,first2,OutIterator result,BinaryFunction f)//f(*first,*first2),返回result.end()
20、数值算法
T accumulate(first,last,T result)//i指向[first,last)中的每一个元素,result = result + *i
T accumulate(first,last,T result,BinaryFunction f)//i指向[first,last)中的每一个元素,对每个*i应用f(result,*i)
T inner_product(first1,last1,first2,T init)//init是内积的初始值,可能是0或其他值。广义内积。{1,2,3} {2,3,4}=1*2+2*3+3*4=20
T inner_product(first1,last1,first2,T init,BinaryFunction op1,BinaryFunction op2)//init是内积的初始值。op1 代替加法,op2代替乘法{1,2,3} {2,3,4}=1 op2 2 op1 2op2..
partial_sum(first,last,result)//广义部分和。{1,2,3} 即:{1,1+2,1+2+3}={1,3,6}
partial_sum(first,last,result,BinaryFunction op)//op代替 +
adjacent_difference(first,last,result)//广义部分差。{1,2,3} 即:{1,2-1,3-2}={1,1,1}
adjacent_difference(first,last,result,BinaryFunction op)//op代替 -
21、通用
swap(a,b)
iter_swap(it1,it2)
min(a,b)
max(a,b)
第七章
1、vector 高效访问。list 高效插入。
set
intset.insert(i);//自动排序,并且元素唯一。
2、容器分类:
序列容器: vector、list、deque(双端队列) 都有push_back(),list和deque还有一个push_front(),vector和deque可以使用operator[],但是list不支持
容器适配器:queue、stack、priority_queue
关联式容器:set、map、multiset、multimap
3、vector
4、back_inserter(v);front_inserter(v);it++,it++,inserter(v,it)
istream_iterator
使用:istreambuf_iterator
5、序列容器:vector、list、deque
typedef Container C ; C s;
s.empty()//判空
s.size()//尺寸
s.max_size()//最大可能尺寸
s.front()//起始元素
s.back()//终止元素
C s(10,1)//10个1
int a[SZ];
c.assign(a,a+SZ);
c.assign(10,2)//10个2
c.push_back(47);
c.pop_back()//删除尾部
typedef C::iterator it=c.begin();it++;
c.insert(it,47);
c.insert(it,3,86);//插入3个86
c.insert(it,c2.bein(),c2.end())
c.erase(it)
c.erase(it,it2)//清除序列中间的元素
c.swap(c2)//两个容器交换所有
c.clear()//删除容器中全部内容
6、向量:vector 索引和迭代操作速度快,除了在最后一个元素之后插入新元素外,向vector中插入一个对象是不可接受的操作。
副作用:当一个vector与存储空间用完以后,为维护其连续的对象数组,它必须在另一个地方重新分配大块新的存储空间,并把以前已有的对象拷贝到新的 存储空间中去。
已分配存储区溢出的代价:1-分配一块新的更大的存储区。2-将旧存储区中的对象拷贝到新开辟的存储区中去,使用拷贝构造函数。3-销毁旧存储区中的所有对象。4-释放旧存储区的内存。
如果vector经常被填满,系统将会为这些拷贝构造函数和析构函数操作的完成付出高昂的代价。
为了支持排序和查找等操作,需要有运算符operator< 、 operator==。int size=atoi("1000");
使用vector最有效的条件是:1-在开始时使用reserve()分配了正确数量的存储区。因此vector不再重新分配存储区。2-仅仅在序列的后端添加或删除元素。利用迭代器向vector中间插入或者删除元素是可能的。
7、双端队列:deque,在序列两端对元素添加和删除。允许快速随机访问。支持operator[]
deque允许在序列两端快速地插入和删除元素,并且在其扩展存储区的时候不需要拷贝和销毁对象的操作。
1-deque没有像vector的那种把所有东西保存在一块连续的内存中的约束。利用多个连续存储块。2-不需要在分配新的存储区是复制并销毁所包含的对象。3-deque有push_front(),pop_front().
for(size_t i=0;i
ostringstream ss;
ss<v[i]=ss.str()+":"+v[i];
}
vector、deque都提供随机访问,使用索引操作符operator[],使用at(),越界则抛出异常。使用at()代价更高一些。
8、链表: list:双向链表数据结构。在任何地方快速插入或删除元素。
list
l.reverse()//倒置
l.sort()//排序
swap(*it1,*it2)
reverse(l.begin(),l.end());//起作用
通用的sort()算法仅仅适用于数组、vector和deque
list
it1=l.begin();
l.splice(it1,l2)//链表l在it1处开始结合链表l2,注意:结合之后l2是空的。
l.splice(it1,l2,it2)//链表l在it1处开始结合链表l2[it2]
l.splice(it1,l2,it2,it3)//链表l在it1处开始结合链表l2从it2开始终止在it3.
l2.remove(l2.back());//删除具有特定值的所有元素
l2.remove(l2.front());
l.merge(l2);//合并成俩个表,
l.sort();
l.unique();//从list中删除所有相邻的重复的对象,唯一的条件就是首先对list进行排序。
l.swap(l2)
9、集合:set仅接受每个元素的一个副本,并对元素排序。set是用一个平衡树数据结构来存储其元素以提供快速的查找。
set
inserter(s,s.begin());
char c; bool isalpha(c);
string word;
s.insert(word)
insert_iterator
while(p!=end)
{
*ii++=*p++:
}
s.insert(word);
ifstream in(fname);
istreambuf_iterator
while (p!=end)
10、堆栈。stack,与queue、priority_queue一起被归类为适配器。建立在另一个序列容器的基础之上。它们将通过调整某一个序列容器以存储自己的数据。
stack
stack
stack
string line;
Stack1.push(line+"\n");
while(!Stack1.empty()){
Stack1.top();
Stack1.pop();
}
可以使用一个vector及其back(),push_back(),pop_back()获得等价的堆栈功能,还拥有vector 的附加功能。
11、队列 queue,容器默认的模板参数是deque.
queue
if(!que.empty())
{
cout<
}
12、优先队列 priority_queue #include
当向一个优先队列中用push压入一个对象时,那个对象根据一个比较函数或函数对象在队列中排序。priority_queue确定在用top查看顶部元素时,该元素将是具有最高优先级的一个元素。处理完该元素,用pop删除。
priority_queue
pqi.push(i);
while(!pqi.empty())
{
cout<
}
改变优先级
priority_queue
0 0 0 0 1 1 2 2 3 3 3 3 3
1 11 11 11 11 12 12 12 12
17 17 17 17 17 18 18 18 1
23 23 23 24 24 24 24 24
priority_queue
24 24 23 23 23 23 2
18 18 17 17 17 17
1 11 11 10 10 10 10
2 2 1 1 1 1 1 1 1 0
堆就是一个优先队列:make_heap(),push_heap(),pop_heap(),priority_queue只是对它的封装。使用sort_heap之后,再使用make_heap,转换成堆。
13、持有二进制位:二进制位集合bitset和逻辑向量vector
bitset参数表示二进制位的个数:bitset<10>与bitset<20>是两种不同的类型,不能将它们两个之间进行比较、赋值等操作。从bitset到一个数的转换用to_ulong()
bitset:
#include
typedef bitset<32> BS;
BS a(rand());
unsigned long ul=a.to_ulong();
string bits("01111110");
BS a(bits);
BS b("11111110");
cout<
cout<<(a|b)<
cout<<(a^b)<
cout<<(BS(a)<<=16)
cout<<(BS(a)>>=16)
cout<
cout<
vector
没有set,reset,只有在vector基础上加了flip
ostringstream os;
copy(vb.begin(), vb.end(),
ostream_iterator
bitset<10> bs(os.str());
cout << "Bitset:" << endl << bs << endl;
14、关联式容器 set/map/multiset/multimap 它们将关键字与值关联起来。set可以看成是没有值的map,它只有关键字。
关联式容器最重要的操作是将对象放进容器。在set的情况下要查看该对象是否已在集合中,在map情况下先查看关键字是否已在map中,如果存在,就为关键字设置关联值。
set
Noisy n;
s.insert(n);
cout<
map
for(i=0;i<10;i++){
nm[i];//自动创建对象,如果使用operator[]查找一个值而它又不存在的话,这个map就会创建一个新的关键字-值对。即:如果实际上想要查询某个对象并不想创建一个新条目,就必须使用个成员函数count()或者find().
}
nm.insert(make_pair(47.n))
nm.count(10);//
map
cout<<(*it).first<<(*it).second;
typedef pair
set
fill_n(inserter(s,s.begin()),10,7);
map
fill_n(inserter(m,m.begin()),10,make_pair(90,120))
copy(m.begin(),m.end(),ostream_iterator
multiset:可以插入每个值的多个对象所有相邻的元素必须毗邻存放。
清除容器的指针:
Container shapes;
shapes.push_back(new Circle);
...
for(it=shapes.begin(),it!=shapes.end();it++)
{
delete *it;
*it=0;
}
#ifndef PURGE_H
#define PURGE_H
#include
template
typename Seq::iterator i;
for(i = c.begin(); i != c.end(); ++i) {
delete *i;
*i = 0;
}
}
// Iterator version:
template
while(begin != end) {
delete *begin;
*begin = 0;
++begin;
}
}
#endif // PURGE_H ///:~
第八章
1、通过指针或引用来决定对象运行时类型的一种方法是使用运行时类型转换。此方法适合把基类指针类型转换为派生类型,也称向下类型转换。
class Bond : public Security {
typedef Security Super;
protected:
enum { OFFSET = 2, TYPEID = BASEID + OFFSET };
public:
bool isA(int id) {
return id == TYPEID || Super::isA(id);
}
static Bond* dynacast(Security* s) {
return (s->isA(TYPEID)) ? static_cast
}
};
dynamic_cast提供类型转换检查。
class Security {
public:
virtual ~Security() {}
};
class Stock : public Security {};
class Bond : public Security {};
class Investment : public Security {
public:
void special() {
std::cout << "special Investment function" <
};
class Metal : public Investment {};
使用指针:
vector
portfolio.push_back(new Metal);
portfolio.push_back(new Investment);
portfolio.push_back(new Bond);
portfolio.push_back(new Stock);
for(vector
portfolio.begin();
it != portfolio.end(); ++it) {
Investment* cm = dynamic_cast
if(cm)
cm->special();
else
cout << "not a Investment" << endl;
}
cout << "cast from intermediate pointer:" << endl;
Security* sp = new Metal;
Investment* cp = dynamic_cast
if(cp) cout << " it's an Investment" << endl;
Metal* mp = dynamic_cast
if(mp) cout << " it's a Metal too!" << endl;
dynamic_cast<目标类型>(操作数),dynamic_cast要求使用的目标对象的类型是多态的,这就要求该类必须至少有一个虚函数。转换失败抛出bad_cast
使用引用:
Metal m;
Security& s = m;
try {
Investment& c = dynamic_cast
cout << "It's an Investment" << endl;
} catch(bad_cast&) {
cout << "s is not an Investment type" << endl;
}
try {
Bond& b = dynamic_cast
cout << "It's a Bond" << endl;
} catch(bad_cast&) {
cout << "It's not a Bond type" << endl;
}
2、type_info ::name(); typeid 返回type_info 类的对象,typeid获得动态类型的名称。const PolyBase *ppdtypeid(*ppb)
3、类型转换到中间层次类型
4、typeid不能与void型指针一起工作。void *v=new Security;//!cout<
5、带模板的RTTI:
#include
#include
using namespace std;
template
public:
Announce() {
cout << typeid(*this).name() << " constructor" << endl;
}
~Announce() {
cout << typeid(*this).name() << " destructor" << endl;
}
};
class X : public Announce<0> {
Announce<1> m1;
Announce<2> m2;
public:
X() { cout << "X::X()" << endl; }
~X() { cout << "X::~X()" << endl; }
};
int main() { X x; } ///:~
//output
class Announce<0> constructor
class Announce<1> constructor
class Announce<2> constructor
X::X()
X::~X()
class Announce<2> destructor
class Announce<1> destructor
class Announce<0> destructor
第九章
1、接口继承:仅仅在一个派生类接口中加入了成员函数的声明。除了析构函数以外,这些声明都是纯虚函数。
class Printable {
public:
virtual ~Printable() {}
virtual void print(ostream&) const = 0;
};
class Intable {
public:
virtual ~Intable() {}
virtual int toInt() const = 0;
};
class Stringable {
public:
virtual ~Stringable() {}
virtual string toString() const = 0;
};
class Able : public Printable, public Intable,
public Stringable {
int myData;
public:
Able(int x) { myData = x; }
void print(ostream& os) const { os << myData; }
int toInt() const { return myData; }
string toString() const {
ostringstream os;
os << myData;
return os.str();
}
};
2、实现继承:在派生类中实现所有的 细节。
protected类型需要一个友元或派生类来使用它。基类的析构函数是虚函数。可以保证派生类的对象正确的销毁。
3、重复子对象
当从某个基类继承时,可以在派生类中得到那个基类的所有数据成员的副本。
class A { int x; };
class B { int y; };
class C : public A, public B { int z; };
int main() {
cout << "sizeof(A) == " << sizeof(A) << endl;
cout << "sizeof(B) == " << sizeof(B) << endl;
cout << "sizeof(C) == " << sizeof(C) << endl;
C c;
cout << "&c == " << &c << endl;
A* ap = &c;
B* bp = &c;
cout << "ap == " << static_cast
cout << "bp == " << static_cast
C* cp = static_cast
cout << "cp == " << static_cast
cout << "bp == cp? " << boolalpha << (bp == cp) << endl;
cp = 0;
bp = cp;
cout << bp << endl;
}
/* Output:
sizeof(A) == 4
sizeof(B) == 4
sizeof(C) == 12
&c == 1245052
ap == 1245052
bp == 1245056
cp == 1245052
bp == cp? true
0
*/ ///:~
如果有多个基类,若果这些基类依次有一个共同的基类,那么将得到顶层基类的两个副本,
如果有多个基类,派生类向上类型转换会出现二义性。
class Top {
int x;
public:
Top(int n) { x = n; }
};
class Left : public Top {
int y;
public:
Left(int m, int n) : Top(m) { y = n; }
};
class Right : public Top {
int z;
public:
Right(int m, int n) : Top(m) { z = n; }
};
class Bottom : public Left, public Right {
int w;
public:
Bottom(int i, int j, int k, int m)
: Left(i, k), Right(j, k) { w = m; }
};
int main() {
Bottom b(1, 2, 3, 4);
cout << sizeof b << endl; // 20
} ///:~
4、虚基类:消除向上类型转换时二义性的问题。
class Top {
protected:
int x;
public:
Top(int n) { x = n; }
virtual ~Top() {}
friend ostream&
operator<<(ostream& os, const Top& t) {
return os << t.x;
}
};
class Left : virtual public Top {
protected:
int y;
public:
Left(int m, int n) : Top(m) { y = n; }
};
class Right : virtual public Top {
protected:
int z;
public:
Right(int m, int n) : Top(m) { z = n; }
};
class Bottom : public Left, public Right {
int w;
public:
Bottom(int i, int j, int k, int m)
: Top(i), Left(0, j), Right(0, k) { w = m; }
friend ostream&
operator<<(ostream& os, const Bottom& b) {
return os << b.x << ',' << b.y << ',' << b.z
<< ',' << b.w;
}
};
int main() {
Bottom b(1, 2, 3, 4);
cout << sizeof b << endl;
cout << b << endl;
cout << static_cast
Top* p = static_cast
cout << *p << endl;
cout << static_cast
cout << dynamic_cast
} ///:~
//output
28
1,2,3,4
0012FF58
1
0012FF6C
dynamic_cast到void*的结果总是确定指向完整对象的地址。
5、含有虚基类的子对象的初始化顺序
1-所有虚基类子对象,按照他们在了定义中出现的位置,从上到下,从左到右初始化。
2-然后非虚基类按通常顺序初始化。
3-所有的成员对象按声明的顺序初始化。
4-完整的对象的构造函数执行。
class M {
public:
M(const string& s) { cout << "M " << s << endl; }
};
class A {
M m;
public:
A(const string& s) : m("in A") {
cout << "A " << s << endl;
}
virtual ~A() {}
};
class B {
M m;
public:
B(const string& s) : m("in B") {
cout << "B " << s << endl;
}
virtual ~B() {}
};
class C {
M m;
public:
C(const string& s) : m("in C") {
cout << "C " << s << endl;
}
virtual ~C() {}
};
class D {
M m;
public:
D(const string& s) : m("in D") {
cout << "D " << s << endl;
}
virtual ~D() {}
};
class E : public A, virtual public B, virtual public C {
M m;
public:
E(const string& s) : A("from E"), B("from E"),
C("from E"), m("in E") {
cout << "E " << s << endl;
}
};
class F : virtual public B, virtual public C, public D {
M m;
public:
F(const string& s) : B("from F"), C("from F"),
D("from F"), m("in F") {
cout << "F " << s << endl;
}
};
class G : public E, public F {
M m;
public:
G(const string& s) : B("from G"), C("from G"),
E("from G"), F("from G"), m("in G") {
cout << "G " << s << endl;
}
};
int main() {
G g("from main");
} ///:~
//output
M in B
B from G
M in C
C from G
M in A
A from E
M in E
E from G
M in D
D from F
M in F
F from G
M in G
G from main
6、名字查找问题的二义性:
类继承了两个同名的函数,没有方法在他们之间选择:
lass Top {
public:
virtual ~Top() {}
};
class Left : virtual public Top {
public:
void f() {}
};
class Right : virtual public Top {
public:
void f() {}
};
class Bottom : public Left, public Right {};
int main() {
Bottom b;
b.f(); // Error here
} ///:~
消除二义性调用的方法,是以基类名来限定函数的调用。
class Top {
public:
virtual ~Top() {}
};
class Left : virtual public Top {
public:
void f() {}
};
class Right : virtual public Top {
public:
void f() {}
};
class Bottom : public Left, public Right {
public:
using Left::f;
};
int main() {
Bottom b;
b.f(); // Calls Left::f()
} ///:~
名称优势:
class A {
public:
virtual ~A() {}
virtual void f() { cout << "A::f\n"; }
};
class B : virtual public A {
public:
void f() { cout << "B::f\n"; }
};
class C : public B {};
class D : public C, virtual public A {};
int main() {
B* p = new D;
p->f(); // Calls B::f()
delete p;
} ///:~
类A是类B的基类,名字B::f比名字A::f占优势。
7、避免使用多继承
关心两个问题:1-是否需要通过新类来显示两个类的公共接口。2-需要向上类型转换成为俩个类型吗?
第十章 设计模式
动机:为了使变化的事物与不变的事物分离开。
1、模式分类
创建型:Creational:用于怎样创建一个对象,隔离对象创建的细节,代码不依赖于对象是什么类型,因此在增加一种新的对象类型时不需要改变代码。Sington、Factory、Builder模式。
单件模式、工厂模式、构建器模式。
结构型:Structural:影响对象之间的连接方式,确保系统的变化不需要改变对象间的连接。Proxy、Adapter模式。代理模式和适配器模式。
行为型:Behavioral:在程序中处理具有特定操作类型的对象。这些对象封装要执行的操作过程。如:解释一种语言、实践一个请求、遍历一个序列、实现一个算法等。
Command、Template Method、State、Strategy、Chain of Responsibility、Observer、Multiple Dispatching、Vistor模式
命令模式、模板方法模式、状态模式、策略模式、职责链模式、观察者模式、多派遣模式、访问者模式。
2、创建型:单件模式:Singleton 它是允许一个类有且仅有一个实例的方法。
#include
using namespace std;
class Singleton {
static Singleton s;
int i;
Singleton(int x) : i(x) { }
Singleton& operator=(Singleton&); // Disallowed
Singleton(const Singleton&); // Disallowed
public:
static Singleton& instance() { return s; }
int getValue() { return i; }
void setValue(int x) { i = x; }
};
Singleton Singleton::s(47);
int main() {
Singleton& s = Singleton::instance();
cout << s.getValue() << endl;
Singleton& s2=Singleton::instance();
cout<
cout<
cout<
//output:
47
47
47
10
10
11
11
1-创建单件模式的关键是防止客户程序员获得任何控制其对象生存期的权利。声明所有构造函数为私有。拷贝构造函数和赋值函数被声明为私有。
2-可以采用静态创建对象,也可以等待,直到客户程序员提出要求再根据要求进行创建。
3-返回引用而不是返回指针,防止用户不小心删除指针。
4-任何情况下,对象应该私有保存。
单件的变体:将在一个成员函数内部的静态对象的创建与单件类结合在一起。
一个类中的任何static静态成员对象都表示一个单件:有且仅有一个对象被创建。
如果一个静态对象依赖于另一个对象,静态对象的初始化顺序是很重要的。
在函数中定义一个静态对象来控制初始化顺序,直到该函数第一次被调用时才进行初始化。如果函数返回一个静态对象的引用,就可以达到单件的效果。
上面程序修改如下:
#include
using namespace std;
class Singleton {
int i;
Singleton(int x) : i(x) { }
Singleton& operator=(Singleton&); // Disallowed
Singleton(const Singleton&); // Disallowed
public:
static Singleton& instance() {
static Singleton s(47);
return s;
}
int getValue() { return i; }
void setValue(int x) { i = x; }
};
int main() {
Singleton& s = Singleton::instance();
cout << s.getValue() << endl;
Singleton& s2=Singleton::instance();
cout<
cout<
cout<
两个单件彼此依赖:可以很好地控制初始化过程。
class Singleton1{
Singleton1(){cout<<"Singleton1()"<
static Singleton1& ref(){
cout<<"前:static Singleton1& ref()"<
cout<<"后:static Singleton1& ref()"<
}
~Singleton1(){cout<<"~Singleton1()"<
class Singleton2{
Singleton1 &s1;
Singleton2(Singleton1& s):s1(s){cout<<"Singleton2(Singleton1& s):s1(s)"<
static Singleton2& ref(){
cout<<"前:static Singleton2& ref()"<
cout<<"后:static Singleton2& ref()"<
}
Singleton1 &f(){
cout<<"Singleton1 &f()"<
}
~Singleton2(){cout<<"~Singleton2()"<
int main(){
Singleton1 &s1=Singleton2::ref().f();
}
//output:
前:static Singleton2& ref()
前:static Singleton1& ref()
Singleton1()
后:static Singleton1& ref()
Singleton2(Singleton1& s):s1(s)
后:static Singleton2& ref()
Singleton1 &f()
~Singleton2()
~Singleton1()
单件的另一种变体:单件角:
MyClass通过下面3个步骤产生一个单件:1-声明其构造函数为私有或保护的。2-声明类Singleton
#include
using namespace std;
template
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
protected:
Singleton() {}
virtual ~Singleton() {}
public:
static T& instance() {
static T theInstance;
return theInstance;
}
};
// A sample class to be made into a Singleton
class MyClass : public Singleton
int x;
protected:
friend class Singleton
MyClass() { x = 0; }
public:
void setValue(int n) { x = n; }
int getValue() const { return x; }
};
int main() {
MyClass& m = MyClass::instance();
cout << m.getValue() << endl;
m.setValue(1);
cout << m.getValue() << endl;
} ///:~
3、行为型:命令模式(Command):选择操作
特点:消除代码间的耦合,消除被调用函数的选择与那个函数被调用位置之间的联系。
主要特点:允许向一个函数或者对象传递一个想要的动作。
命令模式就是一个函数对象:一个作为对象的函数,通过将函数封装为对象,就能够以参数的形式传递给其他函数或者对象。
class Command {
public:
virtual void execute() = 0;
};
class Hello : public Command {
public:
void execute() { cout << "Hello "; }
};
class World : public Command {
public:
void execute() { cout << "World! "; }
};
class IAm : public Command {
public:
void execute() { cout << "I'm the command pattern!"; }
};
// An object that holds commands:
class Macro {
vector
public:
void add(Command* c) { commands.push_back(c); }
void run() {
vector
while(it != commands.end())
(*it++)->execute();
}
};
int main() {
Macro macro;
macro.add(new Hello);
macro.add(new World);
macro.add(new IAm);
macro.run();
} ///:~
4、结构型:代理模式(Proxy):作为其他对象的前端
代理模式和状态模式都提供一个代理类,代码与代理类打交道,而作实际工作的类隐藏在代理类背后。当调用代理类中的一个函数时,代理类转而去调用实现类中相应的函数。从结构上看,代理模式是状态模式的一个特例。
基本思想:代理类派生自一个基类,由平行地派生自同一个基类的一个或多个类提供实际的实现。
当一个代理对象被创建的时候,一个实现对象就分配给了它,代理对象就将函数调用发给实现对象。
从结构上看,代理模式和状态模式的区别:代理模式只有一个实现类,而状态模式有多个实现。应用也不同:代理模式控制对其实现类的访问。而状态模式动态的改变其实现类。
#include
using namespace std;
class ProxyBase {
public:
virtual void f() = 0;
virtual void g() = 0;
virtual void h() = 0;
virtual ~ProxyBase() {}
};
class Implementation : public ProxyBase {
public:
void f() { cout << "Implementation.f()" << endl; }
void g() { cout << "Implementation.g()" << endl; }
void h() { cout << "Implementation.h()" << endl; }
};
class Proxy : public ProxyBase {
ProxyBase* implementation;
public:
Proxy() { implementation = new Implementation(); }
~Proxy() { delete implementation; }
// Forward calls to the implementation:
void f() { implementation->f(); }
void g() { implementation->g(); }
void h() { implementation->h(); }
};
int main() {
Proxy p;
p.f();
p.g();
p.h();
} ///:~
5、行为型:状态模式(State):改变对象的行为
状态模式产生一个改变其类的对象,当发现在大多数或者所有函数中都存在有条件的代码时,这种模式很有用。和代理模式一样,状态模式通过一个前端对象来使用后端实现对象。
测试一个bool变量。
class Creature {
bool isFrog;
public:
Creature() : isFrog(true) {}
void greet() {
if(isFrog)
cout << "Ribbet!" << endl;
else
cout << "Darling!" << endl;
}
void kiss() { isFrog = false; }
};
在所有操作前都必须测试isFrog变量,使用状态对象,是代码简化。
#include
#include
using namespace std;
class Creature {
class State {
public:
virtual string response() = 0;
};
class Frog : public State {
public:
string response() { return "Ribbet!"; }
};
class Prince : public State {
public:
string response() { return "Darling!"; }
};
State* state;
public:
Creature() : state(new Frog()) {}
void greet() {
cout << state->response() << endl;
}
void kiss() {
delete state;
state = new Prince();
}
};
int main() {
Creature creature;
creature.greet();
creature.kiss();
creature.greet();
} ///:~
6、结构型:适配器模式(Adapter)
接受一种类型并且提供一个对其他类型的接口。
创建适配器,接受FibonacciGenerator并产生一个供STL算法使用的迭代器。
class FibonacciGenerator {//斐波那契数列
int n;
int val[2];
public:
FibonacciGenerator() : n(0) { val[0] = val[1] = 0; }
int operator()() {
int result = n > 2 ? val[0] + val[1] : n > 0 ? 1 : 0;
++n;
val[0] = val[1];
val[1] = result;
return result;
}
int count() { return n; }
};
#include
#include
#include
#include "FibonacciGenerator.h"
using namespace std;
class FibonacciAdapter { // Produce an iterator
FibonacciGenerator f;
int length;
public:
FibonacciAdapter(int size) : length(size) {}
class iterator;
friend class iterator;
class iterator : public std::iterator<
std::input_iterator_tag, FibonacciAdapter, ptrdiff_t> {
FibonacciAdapter& ap;
public:
typedef int value_type;
iterator(FibonacciAdapter& a) : ap(a) {}
bool operator==(const iterator&) const {
return ap.f.count() == ap.length;
}
bool operator!=(const iterator& x) const {
return !(*this == x);
}
int operator*() const { return ap.f(); }
iterator& operator++() { return *this; }
iterator operator++(int) { return *this; }
};
iterator begin() { return iterator(*this); }
iterator end() { return iterator(*this); }
};
int main() {
const int SZ = 20;
FibonacciAdapter a1(SZ);
cout << "accumulate: "
<< accumulate(a1.begin(), a1.end(), 0) << endl;
}
7、行为型:模板方法模式(Template Method)
模板方法模式的一个重要特征是它的定义在基类中,并且不能改动。模板方法模式就是坚持相同的代码,它调用基类的不同函数来驱动程序运行。
驱动程序运行的引擎是模板方法模式,这个引擎是主要的事件环,客户程序员只需提供customize1()、customize2()的定义,便可以令应用程序运行。
class ApplicationFramework {
protected:
virtual void customize1() = 0;
virtual void customize2() = 0;
public:
void templateMethod() {
for(int i = 0; i < 5; i++) {
customize1();
customize2();
}
}
};
// Create a new "application":
class MyApp : public ApplicationFramework {
protected:
void customize1() { cout << "Hello "; }
void customize2() { cout << "World!" << endl; }
};
int main() {
MyApp app;
app.templateMethod();
} ///:~
8、行为型:策略模式(Strategy):运行时选择算法
将变化的代码从“坚持相同代码”中分开。策略即:使用多种方法来解决某个问题。
好处:在程序运行时可以加入变化的代码。
class NameStrategy {
public:
virtual void greet() = 0;
};
class SayHi : public NameStrategy {
public:
void greet() {
cout << "Hi! How's it going?" << endl;
}
};
class Ignore : public NameStrategy {
public:
void greet() {
cout << "(Pretend I don't see you)" << endl;
}
};
class Admission : public NameStrategy {
public:
void greet() {
cout << "I'm sorry. I forgot your name." << endl;
}
};
// The "Context" controls the strategy:
class Context {
NameStrategy& strategy;
public:
Context(NameStrategy& strat) : strategy(strat) {}
void greet() { strategy.greet(); }
};
int main() {
SayHi sayhi;
Ignore ignore;
Admission admission;
Context c1(sayhi), c2(ignore), c3(admission);
c1.greet();
c2.greet();
c3.greet();
} ///:~
9、行为型:职责链模式(Chain of Responsibility):尝试采用一系列策略模式,本质:尝试多个解决方法直到找到一个起作用的方法。
职责链可看做是使用策略对象的递归。在职责链中,一个函数调用自身,调用函数的一个不同实现,如此反复直至达到某个终止条件,这个终止套件或者是已到达策略链的地底部或者是找到一个成功的策略。职责链实际上是一个链表,动态创建。
使用自动递归搜索链中每个策略的机制,职责链模式自动找到一个解决方法。
#ifndef PURGE_H
#define PURGE_H
#include
template
typename Seq::iterator i;
for(i = c.begin(); i != c.end(); ++i) {
delete *i;
*i = 0;
}
}
// Iterator version:
template
while(begin != end) {
delete *begin;
*begin = 0;
++begin;
}
}
#endif // PURGE_H ///:~
#include
#include
#include "purge.h"
using namespace std;
enum Answer { NO, YES };
class GimmeStrategy {
public:
virtual Answer canIHave() = 0;
virtual ~GimmeStrategy() {}
};
class AskMom : public GimmeStrategy {
public:
Answer canIHave() {
cout << "Mooom? Can I have this?" << endl;
return NO;
}
};
class AskDad : public GimmeStrategy {
public:
Answer canIHave() {
cout << "Dad, I really need this!" << endl;
return NO;
}
};
class AskGrandpa : public GimmeStrategy {
public:
Answer canIHave() {
cout << "Grandpa, is it my birthday yet?" << endl;
return NO;
}
};
class AskGrandma : public GimmeStrategy {
public:
Answer canIHave() {
cout << "Grandma, I really love you!" << endl;
return YES;
}
};
class Gimme : public GimmeStrategy {
vector
public:
Gimme() {
chain.push_back(new AskMom());
chain.push_back(new AskDad());
chain.push_back(new AskGrandpa());
chain.push_back(new AskGrandma());
}
Answer canIHave() {
vector
while(it != chain.end())
if((*it++)->canIHave() == YES)
return YES;
// Reached end without success...
cout << "Whiiiiinnne!" << endl;
return NO;
}
~Gimme() { purge(chain); }
};
int main() {
Gimme chain;
chain.canIHave();
} ///:~
10、创建型:工厂模式(Factory):封装对象的创建。
将创建对象的代码转到这个工厂中执行,那么在增加新对象时所做的全部工作就是只需要修改工厂。
实现工厂模式的一种方法就是在基类中定义一个静态成员函数。
#include
#include
#include
#include
#include
#include "purge.h"
using namespace std;
class Shape {
public:
virtual void draw() = 0;
virtual void erase() = 0;
virtual ~Shape() {}
class BadShapeCreation : public logic_error {
public:
BadShapeCreation(string type)
: logic_error("Cannot create type " + type) {}
};
static Shape* factory(const string& type)
throw(BadShapeCreation);
};
class Circle : public Shape {
Circle() {} // Private constructor
friend class Shape;
public:
void draw() { cout << "Circle::draw" << endl; }
void erase() { cout << "Circle::erase" << endl; }
~Circle() { cout << "Circle::~Circle" << endl; }
};
class Square : public Shape {
Square() {}
friend class Shape;
public:
void draw() { cout << "Square::draw" << endl; }
void erase() { cout << "Square::erase" << endl; }
~Square() { cout << "Square::~Square" << endl; }
};
Shape* Shape::factory(const string& type)
throw(Shape::BadShapeCreation) {
if(type == "Circle") return new Circle;
if(type == "Square") return new Square;
throw BadShapeCreation(type);
}
char* sl[] = { "Circle", "Square", "Square",
"Circle", "Circle", "Circle", "Square" };
int main() {
vector
try {
for(size_t i = 0; i < sizeof sl / sizeof sl[0]; i++)
shapes.push_back(Shape::factory(sl[i]));
} catch(Shape::BadShapeCreation e) {
cout << e.what() << endl;
purge(shapes);
return EXIT_FAILURE;
}
for(size_t i = 0; i < shapes.size(); i++) {
shapes[i]->draw();
shapes[i]->erase();
}
purge(shapes);
} ///:~
多态工厂:使用不同类的工厂派生自基本类型的工厂。
工厂模式是多态工厂的一个特例。
#include
#include