C ++ 编程思想(卷二) 笔记

来源:互联网 发布:php经典面试题 编辑:程序博客网 时间:2024/04/28 23:37
2013年8月16日夜02:53
第一章
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()会自动被调用。<exception>中定义.terminate调用abort(),导致程序不会正常终止函数,全局对象额静态对象的析构函数不会执行。terminate也会在下面两个条件下执行:局部对象的析构函数抛出异常时,栈正在进行清理工作;或者是全局对象或静态对象的构造函数或析构函数抛出异常。set_terminate函数可以设置自己的terminate函数,自定义的terminator不能有参数,且返回值为void类型。第一次调用返回默认的terminate函数的指针,这样可以在需要的时候恢复原来的terminate。
7、防止资源泄漏,采用方式:1-在构造函数中捕获异常,用于释放资源。2-在对象的构造函数中分配资源,并在对象的析构函数中释放资源。
8、若返回类型为引用,则表示不能返回0.因为不能有空引用。
9、RAII,资源获得式初始化,是一个封装类,用于封装指向分配的对内存的指针,使得程序能够自动释放这些内存。auto_ptr类模板在头文件<memeroy>中定义。auto_ptr<类>
10、从exception类(定义在头文件<exception>中)派生自己定义的标准异常类。两个派生类:logic_error和runtime_error。这两个类在头文件<stdexcept>文件中,派生类接受参数std::string的构造函数。通过exception::what()函数,可以得到保存的消息。因为exception没有参数为string的构造函数,所以用户最好从两个派生类派生自己定义的类。
11、异常规格说明:int fun () throw(big,small);函数可能抛出的异常写在throw之后的括号中。int fun()throw()表示函数不会抛出任何异常。int fun()表示函数有可能抛出任何类型的异常。如果异常不在异常规格说明的异常集中,那么unexcepted会被调用。默认的unexpected调用terminate函数。可以使用set_unexpected函数(头文件<exception>)使用一个函数指针作为参数,这个指针指向的函数没有参数,而且其返回类型为void。set_unexpected函数返回unexpected先前的值,所以可以保存这个值,以后使用它。
12、异常规格说明中包含std::bad_exception 在<exception>中,则unexpected异常会被换成std::bad_exception对象,程序恢复到函数被调用的位置重新开始异常匹配。如果异常规格说明中不包含std::bad_exception,程序会调用terminate函数。VC++中不会调用set_unexpected()函数。
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<<endl; ARG   变种:#define TRACE(ARG) cout<<#ARG"=["<<ARG<<"]"<<endl;


第三章 
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),<cctype>
11、反向查找s.rfind.从后向前查找,不成功返回string::npos
12、从字符串中删除字符:s.erase(0,string::npos),两个默认值,起始位置,删除的个数。s.erase()删除所有。
13、<string>全局函数getline(in,s).使用s.c_str()可以将string类型转换成char * 类型,
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<<setfill(fillc)<<endl;恢复先前的填充。os<<setw(4)<iomanip>
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<<in.rdbuf();输出文件内容到标准输出。rdbuf返回一个指针。
9、ios::beg流的开始位置,ios::cur流的当前位置,ios::end流的末端位置,p表示写指针,g表示读指针。ostream 调用tellp,seekp.  istream 调用tellg,seekg.   ofstream out("",ios::out|ios::binary);out.write(origData[i],STR_LEN). ifstream in("",ios::in|ios::binary);in.read(readData[i],TR_LEN);in.seekg(-STR_LEN,ios::end);//Seek -STR_KEN byte from the end of file
10、char readData[STR_NUM][STR_LEN]={{0}};
11、字符串输入输出流iostringstream直接对内存而不是对文件和标准输出设备进行操作。它使用和cin、cout、相同的读取和格式化函数来操纵内存中的数据。写字符到字符串流,使用ostringstream,从这个流读取字符,可以使用istringstream。头文件<sstream>.epsilon()返回在<limits>中定义的常量,表示双精度数字的机器误差。istringstream s("47 1.414 this is a test");int i;double f;s>>i>>f;  ostringstream将字符串插入动态缓冲区,调用str()将内存中字符串转换string。 cin >> ws; // Throw away white space
  string stuff;
  getline(cin, stuff); // Get rest of the line
  cout<<stuff;
  ostringstream os;
  os << "integer = " << i << endl;
  os << "float = " << f << endl;
  os << "string = " << stuff << endl;
  string result = os.str();
  cout << result << endl;
重载版本的os.str("huaguanglu");cout<<os.str()<<endl;
12、格式化标志:setf()打开标志,unsetf()关闭标志。标志:ios::skipws 跳过空格 ios::showbase打印整型时指出数字的基数(dec/oct/hex)。ios::showpoint显示浮点值的小数点。ios::uppercase显示十六进制时,使用大写。ios::showpos:显示正数前面的'+'。ios::unitbuf:单元缓冲区。立即刷新。cout.setf(ios::showpos)显示正号cout.unsetf(ios::showpos)关闭显示。
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<<endl;cout<<flush;在头文件<iostream>中包含操纵算子:cin>>ws吃掉空格,cout<<hex<<"0x"<<i<<endl;
endl,flush,hex,oct,dec,
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<ulong>::max();<limits>
17、time_t timer;srand(time(&timer));


第五章
1、模板参数:无类型模板参数template<class T,size_t N> class Stack{
T data[N];
size_t count;
public:
void push(const T& t);
};
实例化模板时,为参数N提供一个编译时常数Stack<int ,100> myStack;
2、默认模板参数:template<class T, size_t N=100> class Stack{};实例化:Stack<int> stack;
template<class T, class Allocator=allocator<T> > class vector;vector有两个参数,一个参数表示它持有的包含对象的类型。另一个参数表示vector所使用的分配器。
函数模板不可以使用默认的模板参数。却能使用模板参数作为普通函数的默认参数。
template<class T> T sum(T* b, T* e, T init=T()){}main{int a[]={1,2,3};cout<<sum(a,a+sizeof a/ sizeof *a)<<endl;}参数默认是T(),int()执行零初始化。int a=int();
3、模板类型的模板参数:
template<class T> class Array{
public:
void push_back(const T& t){}
T* begin(){return data;}
T* end(){return data+count;}
};
template<clss T, template<class> class Seq> class Container{
Seq<T> seq;
public:
void append(const T& t){seq.push_back(t);}
T* begin(){return seq.begin();}
T* end(){rturn seq.end();}
}
main()
{
Container<int, Array> container;
}
此时的默认参数需要重新声明:
template<class T, size_t T=10>
template<class T,template<class,size_t = 10> class Seq>
typename Seq<T>::iterator begin(){return seq.begin();}
typename T::id i;
typename作用:
1-typename不是创建一个新类型,而是声明id是一个嵌套类型,然后创建这个类型的对象 i。
class Y{
class id {};
};
创建一个新类型:typedef typename Seq<It>::iterator It;
2-typename代替class
4、<typeinfo> cout<<typeid<T*this>.name(),返回type_info对象。成员模板函数不能为virtual虚类型。
5、min<>(1,4),表示强制使用模板。<cctype>toupper/tolower有一个参数,<iostream>toupper/tolower有两个参数。避免冲突:
1-可以在不包含<iostream>中使用,2-可以使用封装的函数模板:template<class charT> charT strTolower(charT c){return tolower(c);}3-可以使用类型转换:
transform(s.begin(),s.end(),s.begin(),static_cast<int (*)(int)>tolower);
6、模板特化:template<>告诉编译器接下来是模板特化。template<> const char* const&min<const char*>(const char* const &a,const char* const &b){retrn (strcmp(a,b)<0)?a:b;}
7、模板不是代码,是产生代码的指令。防止模板代码膨胀:一个模板化的Stack容器,用int,int *,char*特化,会生成3个版本的Stack代码,可以用void* 进行完全特化,然后从void*实现中派生出所有的其他的指针类型。
8、名称查找问题:编译器第一阶段对模板解析,第二阶段模板实例化。限定名:MyClss::f()/x.f()/p->f()  关联参数查找。若名称是关联的,则它的查找在实例化进行,非限定的关联名称除外,它是一个普通的名称查找,它的查找在定义时进行,比较早。
9、在类中声明一个友元函数,就允许一个类的非成员函数访问这个类的非公有成员。友元函数模板必须提前声明。
template<class T> class Friendly;
template<class T> void f(const Friendly<T>&);
template<class T> class Friendly{
public:
friend void f<>(const Friendly<T>&);//f<>说明f是一个模板
friend void f(const Friendly<T>&);//f说明f是一个普通函数
};
10、模板元编程:编译时编程,在程序开始运行前就已经完成了计算。
template<int n> struct Factorial {
  enum { val = Factorial<n-1>::val * n };
};


template<> struct Factorial<0> {
  enum { val = 1 };
};


int main() {
  cout << Factorial<12>::val << endl; // 479001600
} ///:~
11、模板定义的源代码与它的声明相分离,使用export关键字。
export
template<int n> struct Factorial {
  enum { val = Factorial<n-1>::val * n };
};


第六章
<algorithm>
1、copy: int a[SZ];int b[SZ];copy(a,a+SZ,b);     equal: equal(a,a+SZ,b);相等返回true.
2、vector<int> v1(a,a+SZ),v2(SZ),v3;//构造函数初始化,v1用a初始化,v2用SZ作分配空间大小。v3没有确定大小。equal/copy(v1.begin(),v1.end(),v2.begin()),
copy(v1.begin(),v1.end(),back_inserter(v3)), back_inserter在头文件<iterator>中定义。  equal(v1.begin(),v1.end(),v3.begin())
3、取<=15的数:bool gt15(int x){return 15<x;}  remove_copy_if(a,a+SZ,b,gt15);返回忽略gt15为真的值(b.end())。bool contains_e(const string&s){return s.find('e') != string::npos;}  replace_copy_if(a,a+SZ,b,contains_e,string("kiss"));  返回b.end()         replace_if(a,a+SZ,contains_e,string("kiss"))
4、流迭代器:<iterator> ostream_iterator<int>(cout,'\n'). 
 remove_copy_if(a,a+SZ,ostream_iterator<int>(cout,'\n'),gt15); 
ofstream out();remove_copy_if(a,a+SZ,ostream_iterator<int>(out,'\n'),gt15); 
ifstream in(); remove_copy_if(istream_iterator<int>(in),istream_iterator<int>(),ostream_iterator<int>(cout,'\n'),gt15);  
istream_iterator<int>()默认构造函数表示文件的结束
5、size_t n=count_if(a,a+SZ,gt15);产生>15的整数元素的个数。int *p=find(a,a+SZ,20)搜索一个序列,直到遇到等于第三个参数的元素。返回第一次找到的指针位置。
6、函数对象:它实现起来像函数同时保存状态,使用时却不用考虑函数参数的个数。这种抽象叫函数对象。
<functional> 提供两种类型:unary_function和binary_function.
 remove_copy_if(a,a+SZ,b,bind2nd(greater<int>,15))
int a[]={12,20,12};count_if(a,a+SZ,not1(bind1st(equal_to<int>(),20)))
产生标准函数对象的模板表达式:类型:unary_function和binary_function.
plus<int>() /minus/multiplies/divides/modulus/negate/equal_to/not_equal_to/greater/less/greater_equal/less_equal/logical_and/logical_or/logical_not
tansform(v.begin(),v.end(),v.begin(),bind2nd(multiplies<int>(),10))用10乘以v中每个元素
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<bool> vb;
  transform(d, d + DSZ, back_inserter(vb),
    not1(ptr_fun(isEven)));
  copy(vb.begin(), vb.end(),
    ostream_iterator<bool>(cout, " "));
  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 <algorithm>
#include <functional>
#include <iostream>
#include <vector>
#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<Shape*> vs;
  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<Angle> va;
  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<int>(cout, " "),
    mem_fun_ref(&Angle::mul));
  cout << endl;
  // Output: 0 20 60 120 200
} ///:~
vector<string>v;
vector<string>::ietrator it;
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<string> v1(5);  vector<string> v2;
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<InputIterator1,InputIterator2>   pair在头文件<utility>中定义
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<ForwardIterator1,ForwardIterator2>   pair在头文件<utility>中定义
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、数值算法
<numeric>
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<int> intset; int i=10;
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<string>::iterator it; reverse_iterator it=v.rbegin();rend();
4、back_inserter(v);front_inserter(v);it++,it++,inserter(v,it)
istream_iterator<char>和ostream_iterator<char>会吃掉空白字符。
使用:istreambuf_iterator<char>和ostreambuf_iterator<char>
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");<stdlib>
    使用vector最有效的条件是:1-在开始时使用reserve()分配了正确数量的存储区。因此vector不再重新分配存储区。2-仅仅在序列的后端添加或删除元素。利用迭代器向vector中间插入或者删除元素是可能的。
7、双端队列:deque,在序列两端对元素添加和删除。允许快速随机访问。支持operator[]
    deque允许在序列两端快速地插入和删除元素,并且在其扩展存储区的时候不需要拷贝和销毁对象的操作。
    1-deque没有像vector的那种把所有东西保存在一块连续的内存中的约束。利用多个连续存储块。2-不需要在分配新的存储区是复制并销毁所包含的对象。3-deque有push_front(),pop_front().
<ctime>: clock_t ticks=clock(); ticks=clock()-ticks;cout<<ticks<<endl;
添加行号:
for(size_t i=0;i<v.size();i++)
{
ostringstream ss;
ss<<i;
v[i]=ss.str()+":"+v[i];
}
vector、deque都提供随机访问,使用索引操作符operator[],使用at(),越界则抛出异常。使用at()代价更高一些。
8、链表: list:双向链表数据结构。在任何地方快速插入或删除元素。
list<string> l,l2;
l.reverse()//倒置
l.sort()//排序
swap(*it1,*it2)
reverse(l.begin(),l.end());//起作用
通用的sort()算法仅仅适用于数组、vector和deque
list<string>::iterator it1,it2;
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<string> s;
inserter(s,s.begin());
char c; bool isalpha(c);
string word;
s.insert(word)
insert_iterator<string> ii(word,word.begin())//从何处开始插入
while(p!=end)
{
*ii++=*p++:
}
s.insert(word);
ifstream in(fname);
istreambuf_iterator<char>p(in),end//这个迭代器从流中逐字符地 提取信息。
while (p!=end)
10、堆栈。stack,与queue、priority_queue一起被归类为适配器。建立在另一个序列容器的基础之上。它们将通过调整某一个序列容器以存储自己的数据。
stack<string> Stack1;//默认使用deque
stack<string, vector<string> > Stack2
stack<string, list<string> > Stack3
string line;
Stack1.push(line+"\n");
while(!Stack1.empty()){
Stack1.top();
Stack1.pop();
}
可以使用一个vector及其back(),push_back(),pop_back()获得等价的堆栈功能,还拥有vector 的附加功能。
11、队列 queue,容器默认的模板参数是deque.
queue<string> que;
if(!que.empty())
{
cout<<que.front();
que.pop();
}
12、优先队列 priority_queue #include <queue>
当向一个优先队列中用push压入一个对象时,那个对象根据一个比较函数或函数对象在队列中排序。priority_queue确定在用top查看顶部元素时,该元素将是具有最高优先级的一个元素。处理完该元素,用pop删除。
priority_queue<int> pqi;//
pqi.push(i);
while(!pqi.empty())
{
cout<<pqi.top();
pqi.pop();
}
改变优先级
priority_queue<int,vector<int>,greater<int> > pqi;//
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<int,vector<int>,less<int> > pqi;//===priority_queue<int > pqi;//
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<bool>不同点:1-bitset持有固定二进制位,vector<bool>动态扩展。2-bitset没有迭代器,vector<bool>是vector的特化。3-bitset与STL不相似,vector<bool>类似于类STL 容器。
bitset参数表示二进制位的个数:bitset<10>与bitset<20>是两种不同的类型,不能将它们两个之间进行比较、赋值等操作。从bitset到一个数的转换用to_ulong()
bitset:
#include <bitset>
typedef bitset<32> BS;
BS a(rand());
unsigned long ul=a.to_ulong();
string bits("01111110");
BS a(bits);
BS b("11111110");
cout<<BS(bits)<<endl;//显示一个完整string,不够在前补0至32位,多了则删除后面的。
cout<<BS(bits,2)从第二个字符开始,不够在前补0至32位,多了则删除后面的。
cout<<BS(bits,2,11)从第二个字符开始连续11个字符,不够在前补0至32位,多了则删除后面的。
cout<<a<<endl;//输出二进制a
cout<<(a&b)<<endl;//00000000000000000000000001111110
cout<<(BS(a)&=b)
cout<<(a|b)<<endl;
cout<<(BS(a)|=b)
cout<<(a^b)<<endl;
cout<<(BS(a)^=b)
cout<<(BS(a)<<=16)
cout<<(BS(a)>>=16)
cout<<BS(a).set()//11111111111111111111111111111111
a.test(0)==0, a.test(1)==1//从右往左下标:76543210
cout<<BS(a).set(i)
cout<<BS(a).reset();//00000000000000000000000000000000
cout<BS(a).flip()//按位取反
cout<BS(a).flip(0)//按位取反第0位。
cout<<a.count()//1的个数
cout<<a.any()//有1存在?
cout<<a.none()//没有1存在?
cout<<a.size()//BS 的二进制位数


vector<bool>:是vector模板的特化,
没有set,reset,只有在vector基础上加了flip
 ostringstream os;
 copy(vb.begin(), vb.end(),ostream_iterator<bool>(os, ""));
 bitset<10> bs(os.str());
 cout << "Bitset:" << endl << bs << endl;


14、关联式容器 set/map/multiset/multimap 它们将关键字与值关联起来。set可以看成是没有值的map,它只有关键字。
关联式容器最重要的操作是将对象放进容器。在set的情况下要查看该对象是否已在集合中,在map情况下先查看关键字是否已在map中,如果存在,就为关键字设置关联值。
set<Noisy> s(a,a+SZ);
Noisy n;
s.insert(n);
cout<<s.count(n);//关键字出现的次数:0/1
if(s.find(n)!=s.end())
map<int , Noisy> nm;
for(i=0;i<10;i++){
nm[i];//自动创建对象,如果使用operator[]查找一个值而它又不存在的话,这个map就会创建一个新的关键字-值对。即:如果实际上想要查询某个对象并不想创建一个新条目,就必须使用个成员函数count()或者find().
}
nm.insert(make_pair(47.n))
nm.count(10);//
map<int ,Notify>::iterator it=nm.find(6);//关键字出现的次数:0/1
cout<<(*it).first<<(*it).second;
typedef pair<const Key, T> value_type
set<int>s;
fill_n(inserter(s,s.begin()),10,7);
map<int,int>m
fill_n(inserter(m,m.begin()),10,make_pair(90,120))
copy(m.begin(),m.end(),ostream_iterator<pair<int,int> >(cout,"\n"));


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 <algorithm>


template<class Seq> void purge(Seq& c) {
  typename Seq::iterator i;
  for(i = c.begin(); i != c.end(); ++i) {
    delete *i;
    *i = 0;
  }
}


// Iterator version:
template<class InpIt> void purge(InpIt begin, InpIt end) {
  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<Bond*>(s) : 0;
  }
};
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" <<std::endl;
  }
};


class Metal : public Investment {};


使用指针:
vector<Security*> portfolio;
  portfolio.push_back(new Metal);
  portfolio.push_back(new Investment);
  portfolio.push_back(new Bond);
  portfolio.push_back(new Stock);
  for(vector<Security*>::iterator it =
       portfolio.begin();
       it != portfolio.end(); ++it) {
    Investment* cm = dynamic_cast<Investment*>(*it);
    if(cm)
      cm->special();
    else
      cout << "not a Investment" << endl;
  }
  cout << "cast from intermediate pointer:" << endl;
  Security* sp = new Metal;
  Investment* cp = dynamic_cast<Investment*>(sp);
  if(cp) cout << "  it's an Investment" << endl;
  Metal* mp = dynamic_cast<Metal*>(sp);
  if(mp) cout << "  it's a Metal too!" << endl;


dynamic_cast<目标类型>(操作数),dynamic_cast要求使用的目标对象的类型是多态的,这就要求该类必须至少有一个虚函数。转换失败抛出bad_cast   <typeinfo>异常。


使用引用:
Metal m;
  Security& s = m;
  try {
    Investment& c = dynamic_cast<Investment&>(s);
    cout << "It's an Investment" << endl;
  } catch(bad_cast&) {
    cout << "s is not an Investment type" << endl;
  }
  try {
    Bond& b = dynamic_cast<Bond&>(s);
    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<<typeid(*v).name();//!Security *s=dynamic_cast<Security*>(v);
5、带模板的RTTI:
#include <iostream>
#include <typeinfo>
using namespace std;


template<int id> class Announce {
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<void*>(ap) << endl;
  cout << "bp == " << static_cast<void*>(bp) << endl;
  C* cp = static_cast<C*>(bp);
  cout << "cp == " << static_cast<void*>(cp) << endl;
  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<void*>(&b) << endl;
Top* p = static_cast<Top*>(&b);
cout << *p << endl;
cout << static_cast<void*>(p) << endl;
cout << dynamic_cast<void*>(p) << endl;
} ///:~
//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 <iostream>
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<<s2.getValue()<<endl;
  cout<<s.getValue()<<endl;
  s.setValue(10);
  cout<<s2.getValue()<<endl;
  cout<<s.getValue()<<endl;
  s2.setValue(11);
  cout<<s2.getValue()<<endl;
  cout<<s.getValue()<<endl;
} ///:~
//output:
47
47
47
10
10
11
11
1-创建单件模式的关键是防止客户程序员获得任何控制其对象生存期的权利。声明所有构造函数为私有。拷贝构造函数和赋值函数被声明为私有。
2-可以采用静态创建对象,也可以等待,直到客户程序员提出要求再根据要求进行创建。
3-返回引用而不是返回指针,防止用户不小心删除指针。
4-任何情况下,对象应该私有保存。


单件的变体:将在一个成员函数内部的静态对象的创建与单件类结合在一起。
一个类中的任何static静态成员对象都表示一个单件:有且仅有一个对象被创建。
如果一个静态对象依赖于另一个对象,静态对象的初始化顺序是很重要的。
在函数中定义一个静态对象来控制初始化顺序,直到该函数第一次被调用时才进行初始化。如果函数返回一个静态对象的引用,就可以达到单件的效果。
上面程序修改如下:
#include <iostream>
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<<s2.getValue()<<endl;
cout<<s.getValue()<<endl;
s.setValue(10);
cout<<s2.getValue()<<endl;
cout<<s.getValue()<<endl;
s2.setValue(11);
cout<<s2.getValue()<<endl;
cout<<s.getValue()<<endl;
} ///:~
两个单件彼此依赖:可以很好地控制初始化过程。
class Singleton1{
Singleton1(){cout<<"Singleton1()"<<endl;}
public:
static Singleton1& ref(){
cout<<"前:static Singleton1& ref()"<<endl;
static Singleton1 single;
cout<<"后:static Singleton1& ref()"<<endl;
return single;
}
~Singleton1(){cout<<"~Singleton1()"<<endl;}
};
class Singleton2{
Singleton1 &s1;
Singleton2(Singleton1& s):s1(s){cout<<"Singleton2(Singleton1& s):s1(s)"<<endl;}
public:
static Singleton2& ref(){
cout<<"前:static Singleton2& ref()"<<endl;
static Singleton2 single(Singleton1::ref());
cout<<"后:static Singleton2& ref()"<<endl;
return single;
}
Singleton1 &f(){
cout<<"Singleton1 &f()"<<endl;
return s1;
}
~Singleton2(){cout<<"~Singleton2()"<<endl;}
};
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<MyClass>为友元。3-从SIngleton<MyClass>派生出MyClass.步骤3:这是对模板Singleton中模板参数的静态依赖。类Singleton<MyClass>能被编译器实例化,因为它不依赖MyClass的大小。
#include <iostream>
using namespace std;


template<class T> class Singleton {
  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<MyClass> {
  int x;
protected:
  friend class Singleton<MyClass>;
  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<Command*> commands;
public:
  void add(Command* c) { commands.push_back(c); }
  void run() {
    vector<Command*>::iterator it = commands.begin();
    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 <iostream>
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 <iostream>
#include <string>
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 <iostream>
#include <algorithm>
#include <numeric>
#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 <algorithm>


template<class Seq> void purge(Seq& c) {
  typename Seq::iterator i;
  for(i = c.begin(); i != c.end(); ++i) {
    delete *i;
    *i = 0;
  }
}


// Iterator version:
template<class InpIt> void purge(InpIt begin, InpIt end) {
  while(begin != end) {
    delete *begin;
    *begin = 0;
    ++begin;
  }
}
#endif // PURGE_H ///:~
#include <iostream>
#include <vector>
#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<GimmeStrategy*> chain;
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<GimmeStrategy*>::iterator it = chain.begin();
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 <iostream>
#include <stdexcept>
#include <cstddef>
#include <string>
#include <vector>
#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<Shape*> shapes;
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 <iostream>
#include <map>
#include <string>
#include <vector>
#include <cstddef>
#include "purge.h"
using namespace std;
class Shape {
public:
  virtual void draw() = 0;
  virtual void erase() = 0;
  virtual ~Shape() {}
};
class ShapeFactory {
  virtual Shape* create() = 0;
  static map<string, ShapeFactory*> factories;
public:
  virtual ~ShapeFactory() {}
  friend class ShapeFactoryInitializer;
  static Shape* createShape(const string& id) {
    if(factories.find(id) != factories.end())
      return factories[id]->create();
  }
};
map<string, ShapeFactory*> ShapeFactory::factories;
class Circle : public Shape {
  Circle() {} // Private constructor
  friend class ShapeFactoryInitializer;
  class Factory;
  friend class Factory;
  class Factory : public ShapeFactory {
  public:
    Shape* create() { return new Circle; }
    friend class ShapeFactoryInitializer;
  };
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 ShapeFactoryInitializer;
  class Factory;
  friend class Factory;
  class Factory : public ShapeFactory {
  public:
    Shape* create() { return new Square; }
    friend class ShapeFactoryInitializer;
  };
public:
  void draw() { cout << "Square::draw" << endl; }
  void erase() { cout << "Square::erase" << endl; }
  ~Square() { cout << "Square::~Square" << endl; }
};
// Singleton to initialize the ShapeFactory:
class ShapeFactoryInitializer {
  static ShapeFactoryInitializer si;
  ShapeFactoryInitializer() {
    ShapeFactory::factories["Circle"]= new Circle::Factory;
    ShapeFactory::factories["Square"]= new Square::Factory;
  }
public:
~ShapeFactoryInitializer() {
    map<string, ShapeFactory*>::iterator it =
      ShapeFactory::factories.begin();
    while(it != ShapeFactory::factories.end())
      delete it++->second;
  }
};
ShapeFactoryInitializer ShapeFactoryInitializer::si;
char* sl[] = { "Circle", "Square", "Square",
  "Circle", "Circle", "Circle", "Square" };
int main() {
  vector<Shape*> shapes;
    for(size_t i = 0; i < sizeof sl / sizeof sl[0]; i++)
      shapes.push_back(ShapeFactory::createShape(sl[i]));
  for( i = 0; i < shapes.size(); i++) {
    shapes[i]->draw();
    shapes[i]->erase();
  }
  purge(shapes);
} ///:~
//output:
Circle::draw
Circle::erase
Square::draw
Square::erase
Square::draw
Square::erase
Circle::draw
Circle::erase
Circle::draw
Circle::erase
Circle::draw
Circle::erase
Square::draw
Square::erase
Circle::~Circle
Square::~Square
Square::~Square
Circle::~Circle
Circle::~Circle
Circle::~Circle
Square::~Square


抽象工厂:使用若干工厂方法模式,每个工厂方法模式创建一个不同类型的对象。
class Obstacle {
public:
  virtual void action() = 0;
};


class Player {
public:
  virtual void interactWith(Obstacle*) = 0;
};


class Kitty: public Player {
  virtual void interactWith(Obstacle* ob) {
    cout << "Kitty has encountered a ";
    ob->action();
  }
};


class KungFuGuy: public Player {
  virtual void interactWith(Obstacle* ob) {
    cout << "KungFuGuy now battles against a ";
    ob->action();
  }
};


class Puzzle: public Obstacle {
public:
  void action() { cout << "Puzzle" << endl; }
};


class NastyWeapon: public Obstacle {
public:
  void action() { cout << "NastyWeapon" << endl; }
};


// The abstract factory:
class GameElementFactory {
public:
  virtual Player* makePlayer() = 0;
  virtual Obstacle* makeObstacle() = 0;
};


// Concrete factories:
class KittiesAndPuzzles : public GameElementFactory {
public:
  virtual Player* makePlayer() { return new Kitty; }
  virtual Obstacle* makeObstacle() { return new Puzzle; }
};


class KillAndDismember : public GameElementFactory {
public:
  virtual Player* makePlayer() { return new KungFuGuy; }
  virtual Obstacle* makeObstacle() {
    return new NastyWeapon;
  }
};


class GameEnvironment {
  GameElementFactory* gef;
  Player* p;
  Obstacle* ob;
public:
  GameEnvironment(GameElementFactory* factory)
  : gef(factory), p(factory->makePlayer()),
    ob(factory->makeObstacle()) {}
  void play() { p->interactWith(ob); }
  ~GameEnvironment() {
    delete p;
    delete ob;
    delete gef;
  }
};


int main() {
  GameEnvironment
    g1(new KittiesAndPuzzles),
    g2(new KillAndDismember);
  g1.play();
  g2.play();
}
/* Output:
Kitty has encountered a Puzzle
KungFuGuy now battles against a NastyWeapon */ ///:~


虚函数的思想就是发送一个消息给对象,让对象确定要做正确的事情。
11、创建型:构建器模式(Builder)
目标:将对象的创建与它的表示法分开。构建器模式和抽象工厂模式主要的区别就是,构建器模式一步步创建对象,
功能:将部件组合成为一个完整的产品的算法和部件本身分开,这样就允许通过一个共同借款的不同实现来为不同的产品提供不同的算法。
12、行为型:观察者模式(Observer)
解决一个常见问题:当某些其他对象改变状态时,应该如何处理。
在观察着模式中有两个变化的事件,正在进行观察的对象的数量和更新发生的方式。即观察着模式允许修改这二者而不影响周围的其他代码。
#ifndef OBSERVER_H
#define OBSERVER_H


class Observable;
class Argument {};


class Observer {
public:
  // Called by the observed object, whenever
  // the observed object is changed:
  virtual void update(Observable* o, Argument* arg) = 0;
  virtual ~Observer() {}
};
#endif // OBSERVER_H ///:~
类Obervable只有一个成员函数:update()接口类。当正在被观察的对象认为到了更新其所有观察者的时机时,它将调用此函数。它允许被观察者的对象传递引起更新操作的对象和任何额外的信息。
#ifndef OBSERVABLE_H
#define OBSERVABLE_H
#include <set>
#include "Observer.h"


class Observable {
  bool changed;
  std::set<Observer*> observers;
protected:
  virtual void setChanged() { changed = true; }
  virtual void clearChanged() { changed = false; }
public:
  virtual void addObserver(Observer& o) {
    observers.insert(&o);
  }
  virtual void deleteObserver(Observer& o) {
    observers.erase(&o);
  }
  virtual void deleteObservers() {
    observers.clear();
  }
  virtual int countObservers() {
    return observers.size();
  }
  virtual bool hasChanged() { return changed; }
  // If this object has changed, notify all
  // of its observers:
  virtual void notifyObservers(Argument* arg = 0) {
    if(!hasChanged()) return;
    clearChanged(); // Not "changed" anymore
    std::set<Observer*>::iterator it;
    for(it = observers.begin();it != observers.end(); it++)
      (*it)->update(this, arg);
  }
  virtual ~Observable() {}
};
#endif // OBSERVABLE_H ///:~


13、行为型:多重派遣模式(Multiple dispatching)
好处:在调用的时候能够以简洁的句法表达方式达到预期的效果。
多态只能通过虚函数调用来实现,要发生多重派遣,必须有一个虚函数调用以确定每个未知的类型。
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <ctime>
#include <cstdlib>
#include "purge.h"
using namespace std;


class Paper;
class Scissors;
class Rock;


enum Outcome { WIN, LOSE, DRAW };


ostream& operator<<(ostream& os, const Outcome out) {
  switch(out) {
    default:
    case WIN: return os << "win";
    case LOSE: return os << "lose";
    case DRAW: return os << "draw";
  }
}


class Item {
public:
  virtual Outcome compete(const Item*) = 0;
  virtual Outcome eval(const Paper*) const = 0;
  virtual Outcome eval(const Scissors*) const= 0;
  virtual Outcome eval(const Rock*) const = 0;
  virtual ostream& print(ostream& os) const = 0;
  virtual ~Item() {}
  friend ostream& operator<<(ostream& os, const Item* it) {
    return it->print(os);
  }
};


class Paper : public Item {
public:
  Outcome compete(const Item* it) { return it->eval(this);}
  Outcome eval(const Paper*) const { return DRAW; }
  Outcome eval(const Scissors*) const { return WIN; }
  Outcome eval(const Rock*) const { return LOSE; }
  ostream& print(ostream& os) const {
    return os << "Paper   ";
  }
};


class Scissors : public Item {
public:
  Outcome compete(const Item* it) { return it->eval(this);}
  Outcome eval(const Paper*) const { return LOSE; }
  Outcome eval(const Scissors*) const { return DRAW; }
  Outcome eval(const Rock*) const { return WIN; }
  ostream& print(ostream& os) const {
    return os << "Scissors";
  }
};


class Rock : public Item {
public:
  Outcome compete(const Item* it) { return it->eval(this);}
  Outcome eval(const Paper*) const { return WIN; }
  Outcome eval(const Scissors*) const { return LOSE; }
  Outcome eval(const Rock*) const { return DRAW; }
  ostream& print(ostream& os) const {
    return os << "Rock    ";
  }
};


struct ItemGen {
  Item* operator()() {
    switch(rand() % 3) {
      default:
      case 0: return new Scissors;
      case 1: return new Paper;
      case 2: return new Rock;
    }
  }
};


struct Compete {
  Outcome operator()(Item* a, Item* b) {
    cout << a << "\t" << b << "\t";
    return a->compete(b);
  }
};


int main() {
  srand(time(0)); // Seed the random number generator
  const int sz = 20;
  vector<Item*> v(sz*2);
  generate(v.begin(), v.end(), ItemGen());
  transform(v.begin(), v.begin() + sz,
    v.begin() + sz,
    ostream_iterator<Outcome>(cout, "\n"),
    Compete());
  purge(v);
} ///:~
//output:
003807A8        00382A10        1
003807E0        00382A48        0
00380818        00382A80        2
00382658        00382AB8        0
00382690        00382AF0        0
003826C8        00382B28        1
00382700        00382B60        1
00382738        00382B98        2
00382770        00382BD0        2
003827A8        00382C08        2
003827E0        00382C40        1
00382818        00382C78        0
00382850        00382CB0        1
00382888        00382CE8        0
003828C0        00382D20        2
003828F8        00382D58        2
00382930        00382D90        1
00382968        00382DC8        2
003829A0        00382E00        1
003829D8        00382E38        2


virtual Item::compete函数开始双重派遣。函数compete调用eval执行第二次派遣。
14、行为型:访问者模式(Visitor)
目标:将类继承层次结构上的操作与这个层次结构本身分开。访问者模式建立在双重派遣方案之上。访问者模式允许创建一个独立的类层次结构Visitor而有效的对主类的借口进行扩展。
#include <algorithm>
#include <iostream>
#include <typeinfo>
#include <string>
#include <vector>
#include <ctime>
#include <cstdlib>
#include "purge.h"
using namespace std;


class Gladiolus;
class Renuculus;
class Chrysanthemum;


class Visitor {
public:
  virtual void visit(Gladiolus* f) = 0;
  virtual void visit(Renuculus* f) = 0;
  virtual void visit(Chrysanthemum* f) = 0;
  virtual ~Visitor() {}
};


class Flower {
public:
  virtual void accept(Visitor&) = 0;
  virtual ~Flower() {}
};


class Gladiolus : public Flower {
public:
  virtual void accept(Visitor& v) {
    v.visit(this);
  }
};


class Renuculus : public Flower {
public:
  virtual void accept(Visitor& v) {
    v.visit(this);
  }
};


class Chrysanthemum : public Flower {
public:
  virtual void accept(Visitor& v) {
    v.visit(this);
  }
};


// Add the ability to produce a string:
class StringVal : public Visitor {
  string s;
public:
  operator const string&() { return s; }
  virtual void visit(Gladiolus*) {
    s = "Gladiolus";
  }
  virtual void visit(Renuculus*) {
    s = "Renuculus";
  }
  virtual void visit(Chrysanthemum*) {
    s = "Chrysanthemum";
  }
};


// Add the ability to do "Bee" activities:
class Bee : public Visitor {
public:
  virtual void visit(Gladiolus*) {
    cout << "Bee and Gladiolus" << endl;
  }
  virtual void visit(Renuculus*) {
    cout << "Bee and Renuculus" << endl;
  }
  virtual void visit(Chrysanthemum*) {
    cout << "Bee and Chrysanthemum" << endl;
  }
};


struct FlowerGen {
  Flower* operator()() {
    switch(rand() % 3) {
      default:
      case 0: 
 cout<<"new Gladiolus"<<endl;
 return new Gladiolus;
      case 1: 
  cout<<"new Renuculus"<<endl;
  return new Renuculus;
      case 2:
  cout<<"new Chrysanthemum"<<endl;
  return new Chrysanthemum;
    }
  }
};


int main() {
  srand(time(0)); // Seed the random number generator
  vector<Flower*> v(10);
  generate(v.begin(), v.end(), FlowerGen());
  cout<<endl;
  vector<Flower*>::iterator it;
  // It's almost as if I added a virtual function
  // to produce a Flower string representation:
  StringVal sval;
  for(it = v.begin(); it != v.end(); it++) {
    (*it)->accept(sval);
    cout << " string(sval)"<<string(sval) << endl;
  }
  // Perform "Bee" operation on all Flowers:
  Bee bee;
  for(it = v.begin(); it != v.end(); it++)
 (*it)->accept(bee);
  purge(v);
} ///:~
//output:
new Chrysanthemum
new Chrysanthemum
new Renuculus
new Renuculus
new Gladiolus
new Gladiolus
new Gladiolus
new Renuculus
new Renuculus
new Chrysanthemum


 string(sval)Chrysanthemum
 string(sval)Chrysanthemum
 string(sval)Renuculus
 string(sval)Renuculus
 string(sval)Gladiolus
 string(sval)Gladiolus
 string(sval)Gladiolus
 string(sval)Renuculus
 string(sval)Renuculus
 string(sval)Chrysanthemum
Bee and Chrysanthemum
Bee and Chrysanthemum
Bee and Renuculus
Bee and Renuculus
Bee and Gladiolus
Bee and Gladiolus
Bee and Gladiolus
Bee and Renuculus
Bee and Renuculus
Bee and Chrysanthemum


Flower是主层次结构,Flower的各个子类通过函数accept()得到一个Visitor,Flower主层次结构除了函数accept没有别的操作,因此Flower层次结构的所有功能都将包含在Visitor层次结构中。每个Flower中的accept函数开始一个双重派遣。第一次派遣决定了Flower类型,第二次派遣决定了Visitor类型 


第十一章
1、进程是在其自己的地址空间运行的自含式程序。线程是进程内的单一连续的控制流。因此一个进程可以有多个并发执行的线程。线程运行在一个进程内,所以它们共享内存和其他资源。
2、防止两个线程在临界区访问同一资源,加锁,互斥。 在进入临界区之前获得互斥锁,在临界区的终点释放。
3、原子操作:1-返回int型变量。2-原子操作不能被线程处理机制中断。3-对int型变量增1操作也是原子操作。
4、线程状态:1-新建状态。2-可运行状态。3-阻塞状态。4-死亡状态。
5、变为阻塞状态:原因:1-调用sleep()使线程处于休眠状态。2-已经使用wait()挂起了该线程的运行,在得到signal()或broadcast()消息之前,它不会变为可执行状态。3-线程正在等待某个I/O操作完成。4-线程正在尝试进入一段被一个互斥锁保护的代码块。
6、除了I/O操作,一个任务可以从任何阻塞操作中中断出来。
7、进程间协作,通过互斥锁来同步两个任务的行为,来阻止一个任务干扰另一个任务的资源。
8、死锁发生的条件:1-互斥。线程使用的资源至少有一个必须是不可共享的。2-至少有一个进程必须持有某一种资源。并且同时等待获得正在被另外的进程所持有的资源。3、不能以抢占的方式剥夺一个进程的资源。4、出现一个循环等待。一个进程等待另外的进程所持有的资源,而这个被等待的进程又等待另一个进程所持有的资源。。。
破坏死锁的最容易的方法是破坏4.
9、5个哲学家就餐问题:每个哲学家以特定的顺序拿筷子:先右后左。进入循环等待。解决方法:最后一个哲学家初始化为:先尝试拿左边的筷子,再拿右边的筷子。
10、线程的优点:提供轻量级(100条指令)的执行语境切换,而非重量级(上千条指令)进程语境切换。进程中所有的线程共享同一内存空间。一个轻量级的语境切换只改变了程序执行的先后顺序和局部变量。进程改变-重量级语境切换-必须调换所有内存空间。
0 0
原创粉丝点击