C ++ 编程思想(卷二) 笔记
生活随笔
收集整理的這篇文章主要介紹了
C ++ 编程思想(卷二) 笔记
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
2013年8月16日夜02:53
第一章
1、異常處理是C++的主要特征之一
2、assert():用于開發(fā)階段調(diào)試,#define NDEBUG 使得assert()失效。
3、C語言中錯誤處理信息:1-在函數(shù)中返回錯誤信息。2-使用C庫的信號處理系統(tǒng)signal(),raise()。3-使用C庫的setjmp()和longjmp().信號處理方法和setjmp、longjmp函數(shù)不調(diào)用析構(gòu)函數(shù),對象不能被正確清理。
4、throw 創(chuàng)建程序所拋出對象的一個拷貝。throw表達(dá)式返回這個對象。try/catch異常處理器可以處理某種異常類型和這種異常類型的派生類。并且為避免再次拷貝異常對象,最好通過引用而不是通過值來捕獲異常。通過引用來捕獲異常,基類異常處理器能夠捕獲派生類異常。
5、catch(...){}可以捕獲任何類型的異常。在異常處理器內(nèi)部catch(){throw;}使用不帶參數(shù)的throw可以重新拋出異常。
6、如果沒有一個異常處理器可以捕獲異常,terminate()會自動被調(diào)用。<exception>中定義.terminate調(diào)用abort(),導(dǎo)致程序不會正常終止函數(shù),全局對象額靜態(tài)對象的析構(gòu)函數(shù)不會執(zhí)行。terminate也會在下面兩個條件下執(zhí)行:局部對象的析構(gòu)函數(shù)拋出異常時,棧正在進(jìn)行清理工作;或者是全局對象或靜態(tài)對象的構(gòu)造函數(shù)或析構(gòu)函數(shù)拋出異常。set_terminate函數(shù)可以設(shè)置自己的terminate函數(shù),自定義的terminator不能有參數(shù),且返回值為void類型。第一次調(diào)用返回默認(rèn)的terminate函數(shù)的指針,這樣可以在需要的時候恢復(fù)原來的terminate。
7、防止資源泄漏,采用方式:1-在構(gòu)造函數(shù)中捕獲異常,用于釋放資源。2-在對象的構(gòu)造函數(shù)中分配資源,并在對象的析構(gòu)函數(shù)中釋放資源。
8、若返回類型為引用,則表示不能返回0.因?yàn)椴荒苡锌找谩?
9、RAII,資源獲得式初始化,是一個封裝類,用于封裝指向分配的對內(nèi)存的指針,使得程序能夠自動釋放這些內(nèi)存。auto_ptr類模板在頭文件<memeroy>中定義。auto_ptr<類>
10、從exception類(定義在頭文件<exception>中)派生自己定義的標(biāo)準(zhǔn)異常類。兩個派生類:logic_error和runtime_error。這兩個類在頭文件<stdexcept>文件中,派生類接受參數(shù)std::string的構(gòu)造函數(shù)。通過exception::what()函數(shù),可以得到保存的消息。因?yàn)閑xception沒有參數(shù)為string的構(gòu)造函數(shù),所以用戶最好從兩個派生類派生自己定義的類。
11、異常規(guī)格說明:int fun () throw(big,small);函數(shù)可能拋出的異常寫在throw之后的括號中。int fun()throw()表示函數(shù)不會拋出任何異常。int fun()表示函數(shù)有可能拋出任何類型的異常。如果異常不在異常規(guī)格說明的異常集中,那么unexcepted會被調(diào)用。默認(rèn)的unexpected調(diào)用terminate函數(shù)。可以使用set_unexpected函數(shù)(頭文件<exception>)使用一個函數(shù)指針作為參數(shù),這個指針指向的函數(shù)沒有參數(shù),而且其返回類型為void。set_unexpected函數(shù)返回unexpected先前的值,所以可以保存這個值,以后使用它。
12、異常規(guī)格說明中包含std::bad_exception 在<exception>中,則unexpected異常會被換成std::bad_exception對象,程序恢復(fù)到函數(shù)被調(diào)用的位置重新開始異常匹配。如果異常規(guī)格說明中不包含std::bad_exception,程序會調(diào)用terminate函數(shù)。VC++中不會調(diào)用set_unexpected()函數(shù)。
13、異常規(guī)格說明與繼承。派生類的異常說明應(yīng)該在結(jié)構(gòu)層次上低于基類的異常說明。即基類的異常說明--》派生出派生類的異常說明。異常規(guī)格說明是為非模板準(zhǔn)備的。
14、operator=應(yīng)遵守6個模式:1-確保程序不給自己賦值,如果是的話跳6。2-給指針數(shù)據(jù)成員分配新內(nèi)存。3-從原有的內(nèi)存區(qū)向新分配的內(nèi)存區(qū)拷貝數(shù)據(jù)。4-釋放原有的內(nèi)存。5-更新對象狀態(tài),也就是把指向分配新堆內(nèi)存地址的指針賦值給指針數(shù)據(jù)成員。6-返回*this。
15、當(dāng)delete對象的時候,對象的析構(gòu)函數(shù)會被調(diào)用。不要在析構(gòu)函數(shù)中拋出異常 。
第二章
1、測試套件框架TestSuit,包含兩個主要的類:Test和Suit。Test類保存測試成功和失敗的次數(shù)??梢詮腡est類派生自己的測試對象。只需要重寫成員函數(shù)run()即可,并用test_()來測試。使用report函數(shù)顯示前面的輸出。
2、Test類有3個虛函數(shù):虛析構(gòu)函數(shù)、reset函數(shù),純虛函數(shù)run;基類設(shè)置虛析構(gòu)函數(shù),表示可以通過基類指針釋放在堆上分配的派生類對象。
3、利用宏處理代碼跟蹤:這兩個宏可以完成調(diào)試器的基本功能,跟蹤代碼執(zhí)行,并顯示表達(dá)式的值。
#define TRACE(ARG) cout<<#ARG<<endl; ARG ? 變種:#define TRACE(ARG) cout<<#ARG"=["<<ARG<<"]"<<endl;
第三章?
1、C++字符串string極大減少了C語言編程中3中最常見的錯誤:1-數(shù)組越界。2-通過未被初始化或被賦以錯誤值的指針來訪問數(shù)組元素。3-在釋放了某一數(shù)組原先所分配的存儲單元后仍保留了懸掛指針。
2、創(chuàng)建string對象:1-創(chuàng)建空string對象。2-將字符串傳給構(gòu)造函數(shù)。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(). 當(dāng)前分配的存儲空間的規(guī)模: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]開始查找,默認(rèn)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找第一個與指定數(shù)值中任一個字符匹配,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),兩個默認(rèn)值,起始位置,刪除的個數(shù)。s.erase()刪除所有。
13、<string>全局函數(shù)getline(in,s).使用s.c_str()可以將string類型轉(zhuǎn)換成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 最主要的目的是防止頭文件被重復(fù)包含與編譯。
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);文件指針相對文件首偏移字節(jié)數(shù)。
11-rewind(fp);將指針移至文件開頭。12-memcpy(newdata,data,sizeof()*count);
3、ostream &os;char fillc=os.fill('0');填充'0',返回先前的填充。os<<setfill(fillc)<<endl;恢復(fù)先前的填充。os<<setw(4)<iomanip>
4、按行輸入:成員函數(shù)get(),成員函數(shù)getline(),全局函數(shù)getline ()。1-2-有三個參數(shù):指向緩沖區(qū)的指針、緩沖區(qū)大小、結(jié)束字符:默認(rèn)'\n',while(in.get(buf,SZ) in.get(); 第一個get讀SZ-1個字符,遇到結(jié)束符。用get()跳過輸入流中的結(jié)束符?;蛘呤褂胕gnore(int N=1,char c=EOF),跳過的字符的數(shù)目,默認(rèn)為1,遇到C字符時,函數(shù)退出,默認(rèn)為EOF。 ? while(in.getline(buf,SZ)在遇到結(jié)束字符的時候,兩個都會在結(jié)果緩沖區(qū)末尾存儲一個0,區(qū)別:當(dāng)遇到結(jié)束符,get停止執(zhí)行,不從輸入流中提取結(jié)束符。再調(diào)用get,會遇到同一個結(jié)束符,函數(shù)將立即返回而不會提取輸入。而getline相反,將從輸入流中提取結(jié)束符,但仍然不會把它存儲到結(jié)果緩沖區(qū)中。get的重載版本:1-int get(),沒有參數(shù),返回int類型的下一個字符.2-get(char &),從流中讀取一個字符放到這個參數(shù)中。3-把流對象存儲到基礎(chǔ)的緩沖區(qū)中。
5、處理流錯誤:ios::badbit,發(fā)生致命錯誤,流不能繼續(xù)使用。ios::eofbit,輸入結(jié)束,ctrl+D. ios::failbit,輸入非法數(shù)據(jù),流可以繼續(xù)使用。ios::goodbit:正常。清空標(biāo)志位:myStream.clear();設(shè)置某個標(biāo)志位,重置另一個標(biāo)志位:myStream.clear(ios::failbit|ios::eofbit);
6、打開剛創(chuàng)建的文件:ofstream out("file.out");ifstream in("file.out");對同一個文件打開讀寫要確定關(guān)閉文件。方法:一、使用大括號,是對象離開作用域調(diào)用析構(gòu)函數(shù),{out}in.二、使用out.close().
7、文件打開模式:ios::in打開輸入文件ios::out打開輸出文件ios::app打開一個僅用于追加的輸出文件ios::ate打開一個已存在的文件,并將文件指針指向文件末尾ios::trunc如果文件存在,截?cái)嗯f文件。ios::binary以二進(jìn)制方式打開文件。回車/換行:0x0D/0x0A
8、流緩沖:streambuf對象將<<右側(cè)對象中的字符輸出到左側(cè)的對象中, ?ifstream in("i.cpp");cout<<in.rdbuf();輸出文件內(nèi)容到標(biāo)準(zhǔn)輸出。rdbuf返回一個指針。
9、ios::beg流的開始位置,ios::cur流的當(dāng)前位置,ios::end流的末端位置,p表示寫指針,g表示讀指針。ostream 調(diào)用tellp,seekp. ?istream 調(diào)用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直接對內(nèi)存而不是對文件和標(biāo)準(zhǔn)輸出設(shè)備進(jìn)行操作。它使用和cin、cout、相同的讀取和格式化函數(shù)來操縱內(nèi)存中的數(shù)據(jù)。寫字符到字符串流,使用ostringstream,從這個流讀取字符,可以使用istringstream。頭文件<sstream>.epsilon()返回在<limits>中定義的常量,表示雙精度數(shù)字的機(jī)器誤差。 istringstream s("47 1.414 this is a test");int i;double f;s>>i>>f; ?ostringstream將字符串插入動態(tài)緩沖區(qū),調(diào)用str()將內(nèi)存中字符串轉(zhuǎn)換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、格式化標(biāo)志:setf()打開標(biāo)志,unsetf()關(guān)閉標(biāo)志。標(biāo)志:ios::skipws 跳過空格 ios::showbase打印整型時指出數(shù)字的基數(shù)(dec/oct/hex)。ios::showpoint顯示浮點(diǎn)值的小數(shù)點(diǎn)。ios::uppercase顯示十六進(jìn)制時,使用大寫。ios::showpos:顯示正數(shù)前面的'+'。ios::unitbuf:單元緩沖區(qū)。立即刷新。cout.setf(ios::showpos)顯示正號cout.unsetf(ios::showpos)關(guān)閉顯示。
13、格式化域:ios::basefield (ios::dec使整型數(shù)值的基數(shù)為10,ios::hex使整型數(shù)值的基數(shù)為16,ios::oct使整型數(shù)值的基數(shù)為8).ios::floatfield(ios::scientific以科學(xué)計(jì)數(shù)的形式顯示浮點(diǎn)數(shù).ios::fixed以固定格式顯示浮點(diǎn)數(shù)。)ios::adjustfield(ios::left使數(shù)值左對齊,填充字符右邊空位。ios::right,ios::internal填充字符放在正負(fù)號和數(shù)值之間正負(fù)號左對齊,數(shù)值右對齊),cout.setf(ios::fixed,ios:floatfield);
14、寬度、填充、精度:int ios::width()返回當(dāng)前寬度,默認(rèn)為0,in ios::width(int n)設(shè)定寬度,返回先前。,int ios::fill()返回當(dāng)前填充字符,默認(rèn)為空格,int ios::fill(int n)設(shè)定填充字符,返回先前,int ios::precision()默認(rèn)精度小數(shù)點(diǎn)后面六位,int ios::precision(int n)設(shè)定精度,返回先前。寬度不會截?cái)嘧址?。寬度只?guī)定最小長度。
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()相當(dāng)于ios::setf(),resetiosflags,相當(dāng)于ios::unsetf(),
setbase(base n),n取值8,10,16,輸出的基數(shù)。setfill(char n)相當(dāng)于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、模板參數(shù):無類型模板參數(shù)template<class T,size_t N> class Stack{
T data[N];
size_t count;
public:
void push(const T& t);
};
實(shí)例化模板時,為參數(shù)N提供一個編譯時常數(shù)Stack<int ,100> myStack;
2、默認(rèn)模板參數(shù):template<class T, size_t N=100> class Stack{};實(shí)例化:Stack<int> stack;
template<class T, class Allocator=allocator<T> > class vector;vector有兩個參數(shù),一個參數(shù)表示它持有的包含對象的類型。另一個參數(shù)表示vector所使用的分配器。
函數(shù)模板不可以使用默認(rèn)的模板參數(shù)。卻能使用模板參數(shù)作為普通函數(shù)的默認(rèn)參數(shù)。
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;}參數(shù)默認(rèn)是T(),int()執(zhí)行零初始化。int a=int();
3、模板類型的模板參數(shù):
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;
}
此時的默認(rèn)參數(shù)需要重新聲明:
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不是創(chuàng)建一個新類型,而是聲明id是一個嵌套類型,然后創(chuàng)建這個類型的對象 i。
class Y{
class id {};
};
創(chuàng)建一個新類型:typedef typename Seq<It>::iterator It;
2-typename代替class
4、<typeinfo> cout<<typeid<T*this>.name(),返回type_info對象。成員模板函數(shù)不能為virtual虛類型。
5、min<>(1,4),表示強(qiáng)制使用模板。<cctype>toupper/tolower有一個參數(shù),<iostream>toupper/tolower有兩個參數(shù)。避免沖突:
1-可以在不包含<iostream>中使用,2-可以使用封裝的函數(shù)模板:template<class charT> charT strTolower(charT c){return tolower(c);}3-可以使用類型轉(zhuǎn)換:
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、模板不是代碼,是產(chǎn)生代碼的指令。防止模板代碼膨脹:一個模板化的Stack容器,用int,int *,char*特化,會生成3個版本的Stack代碼,可以用void* 進(jìn)行完全特化,然后從void*實(shí)現(xiàn)中派生出所有的其他的指針類型。
8、名稱查找問題:編譯器第一階段對模板解析,第二階段模板實(shí)例化。限定名:MyClss::f()/x.f()/p->f() ?關(guān)聯(lián)參數(shù)查找。若名稱是關(guān)聯(lián)的,則它的查找在實(shí)例化進(jìn)行,非限定的關(guān)聯(lián)名稱除外,它是一個普通的名稱查找,它的查找在定義時進(jìn)行,比較早。
9、在類中聲明一個友元函數(shù),就允許一個類的非成員函數(shù)訪問這個類的非公有成員。友元函數(shù)模板必須提前聲明。
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是一個普通函數(shù)
};
10、模板元編程:編譯時編程,在程序開始運(yùn)行前就已經(jīng)完成了計(jì)算。
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關(guān)鍵字。
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;//構(gòu)造函數(shù)初始化,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的數(shù):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>()默認(rèn)構(gòu)造函數(shù)表示文件的結(jié)束
5、size_t n=count_if(a,a+SZ,gt15);產(chǎn)生>15的整數(shù)元素的個數(shù)。int *p=find(a,a+SZ,20)搜索一個序列,直到遇到等于第三個參數(shù)的元素。返回第一次找到的指針位置。
6、函數(shù)對象:它實(shí)現(xiàn)起來像函數(shù)同時保存狀態(tài),使用時卻不用考慮函數(shù)參數(shù)的個數(shù)。這種抽象叫函數(shù)對象。
<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)))
產(chǎn)生標(biāo)準(zhǔn)函數(shù)對象的模板表達(dá)式:類型: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、函數(shù)指針適配器ptr_fun()把一個指向函數(shù)的指針轉(zhuǎn)化成一個函數(shù)對象。
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))算法將序列中每一個元素一次傳遞給第三個參數(shù)指示的函數(shù)對象。mem_fun()使用指向成員的一個指針來作為它的參數(shù)。mem_fun_ref()為一個對象直接調(diào)用成員函數(shù)
#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()要求它調(diào)用的函數(shù)返回一個值。不能使用transform()調(diào)用返回值為void的成員函數(shù),也不能調(diào)用只有一個參數(shù)的for_each函數(shù)
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()); 對區(qū)間每個元素調(diào)用gen(). ? generate_n(back_inserter(v2),7,gen())對gen()調(diào)用7次,將返回值賦給由first開始的7個元素。
12、計(jì)數(shù):count(v.begin(),v.end(), value); ?count_if(v.begin(),v.end(),pred)//pred返回true的個數(shù)
13、操作序列:
copy(v.begin(),v.end(),dest.begin())
copy_backward(v.begin(),v.end(),dest.begin())//以相反的順序復(fù)制元素
reverse(v.begin(),v.end())//倒置原序列范圍的元素
reverse_copy(v.begin(),v.end(),dest.begin())
swap_ranges(v.begin().v.end(),v2.begin())//交換相等大小兩個范圍的內(nèi)容
rotate(first,middle,last)//[first,middle)內(nèi)容移至末尾,[middle,last)元素移至開始
rotate_copy(first,middle,last,dest)
next_permutation(first,last)//排列成后繼的排列
next_permutation(first,last,pred)//重載
pre_permutation(first,last)//排列成前驅(qū)的排列
pre_permutation(first,last,pred)//重載
random_shuffle(first,last)//隨機(jī)重排范圍內(nèi)的元素
random_shuffle(first,last,rand)//重載,使用用戶提供的隨機(jī)函數(shù)重排
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)//第二序列是否出現(xiàn)在第一序列范圍之內(nèi),順序完全一致,返回首先出現(xiàn)的位置
search(first1,last1,first2,last2,pred)//比較的每對元素是否使pred為true.
find_end(first1,last1,first2,last2)//第二序列是否是第一序列的子集,返回最后出現(xiàn)的位置
find_end(first1,last1,first2,last2,pred)//比較的每對元素是否使pred為true.返回最后出現(xiàn)的位置
search_n(first,last,value)//找count個連續(xù)的值,與value相等。
search_n(first,last,value,pred)//與value相等的值傳遞給pred,返回true,否則返回last.
min_element(first,last)//最小值首次出現(xiàn)的位置
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、排序和運(yùn)算
排序:
sort(first,last)//升序
sort(first,last,pred)
stablesort(first,last)//升序,保持相等元素的原始順序
stablesort(first,last,pred)
partial_sort(first,middle,last)//對一定數(shù)量元素排序,放入[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)
運(yùn)算:
在已排序的序列中查找
binary_search(first,last,value)
binary_search(first,last,value,pred)
lower_bound(first,last,value)//第一次出現(xiàn)的位置,若沒有,返回應(yīng)該出現(xiàn)的位置
lower_bound(first,last,value,pred)
upper_bound(first,last,value)//超過value最后出現(xiàn)的位一個置,若沒有,返回應(yīng)該出現(xiàn)的位置
upper_bound(first,last,value,pred)
pair<ForwardIterator1,ForwardIterator2> ? pair在頭文件<utility>中定義
equal_range(first,last,value)//結(jié)合了lower_bound和upper_bound,返回一個指出value在已排序的范圍[first,last)中首次出現(xiàn)和超越最后出現(xiàn)的pair,如果沒有找到,這兩個迭代器都指 //出value在該序列中應(yīng)該出現(xiàn)的位置。
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)
在已排序的序列上進(jìn)行集合運(yùn)算
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、堆運(yùn)算
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)//轉(zhuǎn)化成普通的排列順序,是不穩(wěn)定的排序
sort_heap(first,last,pred)
19、對某一范圍內(nèi)的所有元素進(jìn)行運(yùn)算
UnaryFuntion for_each(first,last,UnaryFuntion f);//對范圍中每個元素應(yīng)用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、數(shù)值算法
<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應(yīng)用f(result,*i)
T inner_product(first1,last1,first2,T init)//init是內(nèi)積的初始值,可能是0或其他值。廣義內(nèi)積。{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是內(nèi)積的初始值。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(雙端隊(duì)列) 都有push_back(),list和deque還有一個push_front(),vector和deque可以使用operator[],但是list不支持
容器適配器:queue、stack、priority_queue
關(guān)聯(lián)式容器: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()//刪除容器中全部內(nèi)容
6、向量:vector 索引和迭代操作速度快,除了在最后一個元素之后插入新元素外,向vector中插入一個對象是不可接受的操作。
? ? 副作用:當(dāng)一個vector與存儲空間用完以后,為維護(hù)其連續(xù)的對象數(shù)組,它必須在另一個地方重新分配大塊新的存儲空間,并把以前已有的對象拷貝到新的 存儲空間中去。
? ? 已分配存儲區(qū)溢出的代價(jià):1-分配一塊新的更大的存儲區(qū)。2-將舊存儲區(qū)中的對象拷貝到新開辟的存儲區(qū)中去,使用拷貝構(gòu)造函數(shù)。3-銷毀舊存儲區(qū)中的所有對象。4-釋放舊存儲區(qū)的內(nèi)存。
? ? 如果vector經(jīng)常被填滿,系統(tǒng)將會為這些拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù)操作的完成付出高昂的代價(jià)。
? ? 為了支持排序和查找等操作,需要有運(yùn)算符operator< 、 operator==。int size=atoi("1000");<stdlib>
? ? 使用vector最有效的條件是:1-在開始時使用reserve()分配了正確數(shù)量的存儲區(qū)。因此vector不再重新分配存儲區(qū)。2-僅僅在序列的后端添加或刪除元素。利用迭代器向vector中間插入或者刪除元素是可能的。
7、雙端隊(duì)列:deque,在序列兩端對元素添加和刪除。允許快速隨機(jī)訪問。支持operator[]
? ? deque允許在序列兩端快速地插入和刪除元素,并且在其擴(kuò)展存儲區(qū)的時候不需要拷貝和銷毀對象的操作。
? ? 1-deque沒有像vector的那種把所有東西保存在一塊連續(xù)的內(nèi)存中的約束。利用多個連續(xù)存儲塊。2-不需要在分配新的存儲區(qū)是復(fù)制并銷毀所包含的對象。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都提供隨機(jī)訪問,使用索引操作符operator[],使用at(),越界則拋出異常。使用at()代價(jià)更高一些。
8、鏈表: list:雙向鏈表數(shù)據(jù)結(jié)構(gòu)。在任何地方快速插入或刪除元素。
list<string> l,l2;
l.reverse()//倒置
l.sort()//排序
swap(*it1,*it2)
reverse(l.begin(),l.end());//起作用
通用的sort()算法僅僅適用于數(shù)組、vector和deque
list<string>::iterator it1,it2;
it1=l.begin();
l.splice(it1,l2)//鏈表l在it1處開始結(jié)合鏈表l2,注意:結(jié)合之后l2是空的。
l.splice(it1,l2,it2)//鏈表l在it1處開始結(jié)合鏈表l2[it2]
l.splice(it1,l2,it2,it3)//鏈表l在it1處開始結(jié)合鏈表l2從it2開始終止在it3.
l2.remove(l2.back());//刪除具有特定值的所有元素
l2.remove(l2.front());
?l.merge(l2);//合并成倆個表,
?l.sort();
?l.unique();//從list中刪除所有相鄰的重復(fù)的對象,唯一的條件就是首先對list進(jìn)行排序。
l.swap(l2)
9、集合:set僅接受每個元素的一個副本,并對元素排序。set是用一個平衡樹數(shù)據(jù)結(jié)構(gòu)來存儲其元素以提供快速的查找。
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一起被歸類為適配器。建立在另一個序列容器的基礎(chǔ)之上。它們將通過調(diào)整某一個序列容器以存儲自己的數(shù)據(jù)。
stack<string> Stack1;//默認(rèn)使用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()獲得等價(jià)的堆棧功能,還擁有vector 的附加功能。
11、隊(duì)列 queue,容器默認(rèn)的模板參數(shù)是deque.
queue<string> que;
if(!que.empty())
{
cout<<que.front();
que.pop();
}
12、優(yōu)先隊(duì)列 priority_queue #include <queue>
當(dāng)向一個優(yōu)先隊(duì)列中用push壓入一個對象時,那個對象根據(jù)一個比較函數(shù)或函數(shù)對象在隊(duì)列中排序。priority_queue確定在用top查看頂部元素時,該元素將是具有最高優(yōu)先級的一個元素。處理完該元素,用pop刪除。
priority_queue<int> pqi;//
pqi.push(i);
while(!pqi.empty())
{
cout<<pqi.top();
pqi.pop();
}
改變優(yōu)先級
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
堆就是一個優(yōu)先隊(duì)列:make_heap(),push_heap(),pop_heap(),priority_queue只是對它的封裝。使用sort_heap之后,再使用make_heap,轉(zhuǎn)換成堆。
13、持有二進(jìn)制位:二進(jìn)制位集合bitset和邏輯向量vector<bool>不同點(diǎn):1-bitset持有固定二進(jìn)制位,vector<bool>動態(tài)擴(kuò)展。2-bitset沒有迭代器,vector<bool>是vector的特化。3-bitset與STL不相似,vector<bool>類似于類STL 容器。
bitset參數(shù)表示二進(jìn)制位的個數(shù):bitset<10>與bitset<20>是兩種不同的類型,不能將它們兩個之間進(jìn)行比較、賦值等操作。從bitset到一個數(shù)的轉(zhuǎn)換用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,不夠在前補(bǔ)0至32位,多了則刪除后面的。
cout<<BS(bits,2)從第二個字符開始,不夠在前補(bǔ)0至32位,多了則刪除后面的。
cout<<BS(bits,2,11)從第二個字符開始連續(xù)11個字符,不夠在前補(bǔ)0至32位,多了則刪除后面的。
cout<<a<<endl;//輸出二進(jìn)制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//從右往左下標(biāo):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的個數(shù)
cout<<a.any()//有1存在?
cout<<a.none()//沒有1存在?
cout<<a.size()//BS 的二進(jìn)制位數(shù)
vector<bool>:是vector模板的特化,
沒有set,reset,只有在vector基礎(chǔ)上加了flip
?ostringstream os;
?copy(vb.begin(), vb.end(),ostream_iterator<bool>(os, ""));
?bitset<10> bs(os.str());
?cout << "Bitset:" << endl << bs << endl;
14、關(guān)聯(lián)式容器 set/map/multiset/multimap 它們將關(guān)鍵字與值關(guān)聯(lián)起來。set可以看成是沒有值的map,它只有關(guān)鍵字。
關(guān)聯(lián)式容器最重要的操作是將對象放進(jìn)容器。在set的情況下要查看該對象是否已在集合中,在map情況下先查看關(guān)鍵字是否已在map中,如果存在,就為關(guān)鍵字設(shè)置關(guān)聯(lián)值。
set<Noisy> s(a,a+SZ);
Noisy n;
s.insert(n);
cout<<s.count(n);//關(guān)鍵字出現(xiàn)的次數(shù):0/1
if(s.find(n)!=s.end())
map<int , Noisy> nm;
for(i=0;i<10;i++){
nm[i];//自動創(chuàng)建對象,如果使用operator[]查找一個值而它又不存在的話,這個map就會創(chuàng)建一個新的關(guān)鍵字-值對。即:如果實(shí)際上想要查詢某個對象并不想創(chuàng)建一個新條目,就必須使用個成員函數(shù)count()或者find().
}
nm.insert(make_pair(47.n))
nm.count(10);//
map<int ,Notify>::iterator it=nm.find(6);//關(guān)鍵字出現(xiàn)的次數(shù):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、通過指針或引用來決定對象運(yùn)行時類型的一種方法是使用運(yùn)行時類型轉(zhuǎn)換。此方法適合把基類指針類型轉(zhuǎn)換為派生類型,也稱向下類型轉(zhuǎn)換。
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提供類型轉(zhuǎn)換檢查。
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<目標(biāo)類型>(操作數(shù)),dynamic_cast要求使用的目標(biāo)對象的類型是多態(tài)的,這就要求該類必須至少有一個虛函數(shù)。轉(zhuǎn)換失敗拋出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獲得動態(tài)類型的名稱。const PolyBase *ppdtypeid(*ppb)
3、類型轉(zhuǎn)換到中間層次類型
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、接口繼承:僅僅在一個派生類接口中加入了成員函數(shù)的聲明。除了析構(gòu)函數(shù)以外,這些聲明都是純虛函數(shù)。
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、實(shí)現(xiàn)繼承:在派生類中實(shí)現(xiàn)所有的 細(xì)節(jié)。
protected類型需要一個友元或派生類來使用它?;惖奈鰳?gòu)函數(shù)是虛函數(shù)。可以保證派生類的對象正確的銷毀。
3、重復(fù)子對象
當(dāng)從某個基類繼承時,可以在派生類中得到那個基類的所有數(shù)據(jù)成員的副本。
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
*/ ///:~
如果有多個基類,若果這些基類依次有一個共同的基類,那么將得到頂層基類的兩個副本,
如果有多個基類,派生類向上類型轉(zhuǎn)換會出現(xiàn)二義性。
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、虛基類:消除向上類型轉(zhuǎn)換時二義性的問題。
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*的結(jié)果總是確定指向完整對象的地址。
5、含有虛基類的子對象的初始化順序
1-所有虛基類子對象,按照他們在了定義中出現(xiàn)的位置,從上到下,從左到右初始化。
2-然后非虛基類按通常順序初始化。
3-所有的成員對象按聲明的順序初始化。
4-完整的對象的構(gòu)造函數(shù)執(zhí)行。
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、名字查找問題的二義性:
類繼承了兩個同名的函數(shù),沒有方法在他們之間選擇:
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
} ///:~
消除二義性調(diào)用的方法,是以基類名來限定函數(shù)的調(diào)用。
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()
} ///:~
名稱優(yōu)勢:
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占優(yōu)勢。
7、避免使用多繼承
關(guān)心兩個問題:1-是否需要通過新類來顯示兩個類的公共接口。2-需要向上類型轉(zhuǎn)換成為倆個類型嗎?
第十章 設(shè)計(jì)模式
動機(jī):為了使變化的事物與不變的事物分離開。
1、模式分類
創(chuàng)建型:Creational:用于怎樣創(chuàng)建一個對象,隔離對象創(chuàng)建的細(xì)節(jié),代碼不依賴于對象是什么類型,因此在增加一種新的對象類型時不需要改變代碼。Sington、Factory、Builder模式。
單件模式、工廠模式、構(gòu)建器模式。
結(jié)構(gòu)型:Structural:影響對象之間的連接方式,確保系統(tǒng)的變化不需要改變對象間的連接。Proxy、Adapter模式。代理模式和適配器模式。
行為型:Behavioral:在程序中處理具有特定操作類型的對象。這些對象封裝要執(zhí)行的操作過程。如:解釋一種語言、實(shí)踐一個請求、遍歷一個序列、實(shí)現(xiàn)一個算法等。
Command、Template Method、State、Strategy、Chain of Responsibility、Observer、Multiple Dispatching、Vistor模式
命令模式、模板方法模式、狀態(tài)模式、策略模式、職責(zé)鏈模式、觀察者模式、多派遣模式、訪問者模式。
2、創(chuàng)建型:單件模式:Singleton ? 它是允許一個類有且僅有一個實(shí)例的方法。
#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-創(chuàng)建單件模式的關(guān)鍵是防止客戶程序員獲得任何控制其對象生存期的權(quán)利。聲明所有構(gòu)造函數(shù)為私有??截悩?gòu)造函數(shù)和賦值函數(shù)被聲明為私有。
2-可以采用靜態(tài)創(chuàng)建對象,也可以等待,直到客戶程序員提出要求再根據(jù)要求進(jìn)行創(chuàng)建。
3-返回引用而不是返回指針,防止用戶不小心刪除指針。
4-任何情況下,對象應(yīng)該私有保存。
單件的變體:將在一個成員函數(shù)內(nèi)部的靜態(tài)對象的創(chuàng)建與單件類結(jié)合在一起。
一個類中的任何static靜態(tài)成員對象都表示一個單件:有且僅有一個對象被創(chuàng)建。
如果一個靜態(tài)對象依賴于另一個對象,靜態(tài)對象的初始化順序是很重要的。
在函數(shù)中定義一個靜態(tài)對象來控制初始化順序,直到該函數(shù)第一次被調(diào)用時才進(jìn)行初始化。如果函數(shù)返回一個靜態(tài)對象的引用,就可以達(dá)到單件的效果。
上面程序修改如下:
#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個步驟產(chǎn)生一個單件:1-聲明其構(gòu)造函數(shù)為私有或保護(hù)的。2-聲明類Singleton<MyClass>為友元。3-從SIngleton<MyClass>派生出MyClass.步驟3:這是對模板Singleton中模板參數(shù)的靜態(tài)依賴。類Singleton<MyClass>能被編譯器實(shí)例化,因?yàn)樗灰蕾嘙yClass的大小。
#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):選擇操作
特點(diǎn):消除代碼間的耦合,消除被調(diào)用函數(shù)的選擇與那個函數(shù)被調(diào)用位置之間的聯(lián)系。
主要特點(diǎn):允許向一個函數(shù)或者對象傳遞一個想要的動作。
命令模式就是一個函數(shù)對象:一個作為對象的函數(shù),通過將函數(shù)封裝為對象,就能夠以參數(shù)的形式傳遞給其他函數(shù)或者對象。
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、結(jié)構(gòu)型:代理模式(Proxy):作為其他對象的前端
代理模式和狀態(tài)模式都提供一個代理類,代碼與代理類打交道,而作實(shí)際工作的類隱藏在代理類背后。當(dāng)調(diào)用代理類中的一個函數(shù)時,代理類轉(zhuǎn)而去調(diào)用實(shí)現(xiàn)類中相應(yīng)的函數(shù)。從結(jié)構(gòu)上看,代理模式是狀態(tài)模式的一個特例。
基本思想:代理類派生自一個基類,由平行地派生自同一個基類的一個或多個類提供實(shí)際的實(shí)現(xiàn)。
當(dāng)一個代理對象被創(chuàng)建的時候,一個實(shí)現(xiàn)對象就分配給了它,代理對象就將函數(shù)調(diào)用發(fā)給實(shí)現(xiàn)對象。
從結(jié)構(gòu)上看,代理模式和狀態(tài)模式的區(qū)別:代理模式只有一個實(shí)現(xiàn)類,而狀態(tài)模式有多個實(shí)現(xiàn)。應(yīng)用也不同:代理模式控制對其實(shí)現(xiàn)類的訪問。而狀態(tài)模式動態(tài)的改變其實(shí)現(xiàn)類。
#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、行為型:狀態(tài)模式(State):改變對象的行為
狀態(tài)模式產(chǎn)生一個改變其類的對象,當(dāng)發(fā)現(xiàn)在大多數(shù)或者所有函數(shù)中都存在有條件的代碼時,這種模式很有用。和代理模式一樣,狀態(tài)模式通過一個前端對象來使用后端實(shí)現(xiàn)對象。
測試一個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變量,使用狀態(tài)對象,是代碼簡化。
#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、結(jié)構(gòu)型:適配器模式(Adapter)
接受一種類型并且提供一個對其他類型的接口。
創(chuàng)建適配器,接受FibonacciGenerator并產(chǎn)生一個供STL算法使用的迭代器。
class FibonacciGenerator {//斐波那契數(shù)列
? 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)
模板方法模式的一個重要特征是它的定義在基類中,并且不能改動。模板方法模式就是堅(jiān)持相同的代碼,它調(diào)用基類的不同函數(shù)來驅(qū)動程序運(yùn)行。
驅(qū)動程序運(yùn)行的引擎是模板方法模式,這個引擎是主要的事件環(huán),客戶程序員只需提供customize1()、customize2()的定義,便可以令應(yīng)用程序運(yùn)行。
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):運(yùn)行時選擇算法
將變化的代碼從“堅(jiān)持相同代碼”中分開。策略即:使用多種方法來解決某個問題。
好處:在程序運(yùn)行時可以加入變化的代碼。
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、行為型:職責(zé)鏈模式(Chain of Responsibility):嘗試采用一系列策略模式,本質(zhì):嘗試多個解決方法直到找到一個起作用的方法。
職責(zé)鏈可看做是使用策略對象的遞歸。在職責(zé)鏈中,一個函數(shù)調(diào)用自身,調(diào)用函數(shù)的一個不同實(shí)現(xiàn),如此反復(fù)直至達(dá)到某個終止條件,這個終止套件或者是已到達(dá)策略鏈的地底部或者是找到一個成功的策略。職責(zé)鏈實(shí)際上是一個鏈表,動態(tài)創(chuàng)建。
使用自動遞歸搜索鏈中每個策略的機(jī)制,職責(zé)鏈模式自動找到一個解決方法。
#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、創(chuàng)建型:工廠模式(Factory):封裝對象的創(chuàng)建。
將創(chuàng)建對象的代碼轉(zhuǎn)到這個工廠中執(zhí)行,那么在增加新對象時所做的全部工作就是只需要修改工廠。
實(shí)現(xiàn)工廠模式的一種方法就是在基類中定義一個靜態(tài)成員函數(shù)。
#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);
} ///:~
多態(tài)工廠:使用不同類的工廠派生自基本類型的工廠。
工廠模式是多態(tài)工廠的一個特例。
#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
抽象工廠:使用若干工廠方法模式,每個工廠方法模式創(chuàng)建一個不同類型的對象。
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 */ ///:~
虛函數(shù)的思想就是發(fā)送一個消息給對象,讓對象確定要做正確的事情。
11、創(chuàng)建型:構(gòu)建器模式(Builder)
目標(biāo):將對象的創(chuàng)建與它的表示法分開。構(gòu)建器模式和抽象工廠模式主要的區(qū)別就是,構(gòu)建器模式一步步創(chuàng)建對象,
功能:將部件組合成為一個完整的產(chǎn)品的算法和部件本身分開,這樣就允許通過一個共同借款的不同實(shí)現(xiàn)來為不同的產(chǎn)品提供不同的算法。
12、行為型:觀察者模式(Observer)
解決一個常見問題:當(dāng)某些其他對象改變狀態(tài)時,應(yīng)該如何處理。
在觀察著模式中有兩個變化的事件,正在進(jìn)行觀察的對象的數(shù)量和更新發(fā)生的方式。即觀察著模式允許修改這二者而不影響周圍的其他代碼。
#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只有一個成員函數(shù):update()接口類。當(dāng)正在被觀察的對象認(rèn)為到了更新其所有觀察者的時機(jī)時,它將調(diào)用此函數(shù)。它允許被觀察者的對象傳遞引起更新操作的對象和任何額外的信息。
#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)
好處:在調(diào)用的時候能夠以簡潔的句法表達(dá)方式達(dá)到預(yù)期的效果。
多態(tài)只能通過虛函數(shù)調(diào)用來實(shí)現(xiàn),要發(fā)生多重派遣,必須有一個虛函數(shù)調(diào)用以確定每個未知的類型。
#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函數(shù)開始雙重派遣。函數(shù)compete調(diào)用eval執(zhí)行第二次派遣。
14、行為型:訪問者模式(Visitor)
目標(biāo):將類繼承層次結(jié)構(gòu)上的操作與這個層次結(jié)構(gòu)本身分開。訪問者模式建立在雙重派遣方案之上。訪問者模式允許創(chuàng)建一個獨(dú)立的類層次結(jié)構(gòu)Visitor而有效的對主類的借口進(jìn)行擴(kuò)展。
#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是主層次結(jié)構(gòu),Flower的各個子類通過函數(shù)accept()得到一個Visitor,Flower主層次結(jié)構(gòu)除了函數(shù)accept沒有別的操作,因此Flower層次結(jié)構(gòu)的所有功能都將包含在Visitor層次結(jié)構(gòu)中。每個Flower中的accept函數(shù)開始一個雙重派遣。第一次派遣決定了Flower類型,第二次派遣決定了Visitor類型?
第十一章
1、進(jìn)程是在其自己的地址空間運(yùn)行的自含式程序。線程是進(jìn)程內(nèi)的單一連續(xù)的控制流。因此一個進(jìn)程可以有多個并發(fā)執(zhí)行的線程。線程運(yùn)行在一個進(jìn)程內(nèi),所以它們共享內(nèi)存和其他資源。
2、防止兩個線程在臨界區(qū)訪問同一資源,加鎖,互斥。 在進(jìn)入臨界區(qū)之前獲得互斥鎖,在臨界區(qū)的終點(diǎn)釋放。
3、原子操作:1-返回int型變量。2-原子操作不能被線程處理機(jī)制中斷。3-對int型變量增1操作也是原子操作。
4、線程狀態(tài):1-新建狀態(tài)。2-可運(yùn)行狀態(tài)。3-阻塞狀態(tài)。4-死亡狀態(tài)。
5、變?yōu)樽枞麪顟B(tài):原因:1-調(diào)用sleep()使線程處于休眠狀態(tài)。2-已經(jīng)使用wait()掛起了該線程的運(yùn)行,在得到signal()或broadcast()消息之前,它不會變?yōu)榭蓤?zhí)行狀態(tài)。3-線程正在等待某個I/O操作完成。4-線程正在嘗試進(jìn)入一段被一個互斥鎖保護(hù)的代碼塊。
6、除了I/O操作,一個任務(wù)可以從任何阻塞操作中中斷出來。
7、進(jìn)程間協(xié)作,通過互斥鎖來同步兩個任務(wù)的行為,來阻止一個任務(wù)干擾另一個任務(wù)的資源。
8、死鎖發(fā)生的條件:1-互斥。線程使用的資源至少有一個必須是不可共享的。2-至少有一個進(jìn)程必須持有某一種資源。并且同時等待獲得正在被另外的進(jìn)程所持有的資源。3、不能以搶占的方式剝奪一個進(jìn)程的資源。4、出現(xiàn)一個循環(huán)等待。一個進(jìn)程等待另外的進(jìn)程所持有的資源,而這個被等待的進(jìn)程又等待另一個進(jìn)程所持有的資源。。。
破壞死鎖的最容易的方法是破壞4.
9、5個哲學(xué)家就餐問題:每個哲學(xué)家以特定的順序拿筷子:先右后左。進(jìn)入循環(huán)等待。解決方法:最后一個哲學(xué)家初始化為:先嘗試拿左邊的筷子,再拿右邊的筷子。
10、線程的優(yōu)點(diǎn):提供輕量級(100條指令)的執(zhí)行語境切換,而非重量級(上千條指令)進(jìn)程語境切換。進(jìn)程中所有的線程共享同一內(nèi)存空間。一個輕量級的語境切換只改變了程序執(zhí)行的先后順序和局部變量。進(jìn)程改變-重量級語境切換-必須調(diào)換所有內(nèi)存空間。
第一章
1、異常處理是C++的主要特征之一
2、assert():用于開發(fā)階段調(diào)試,#define NDEBUG 使得assert()失效。
3、C語言中錯誤處理信息:1-在函數(shù)中返回錯誤信息。2-使用C庫的信號處理系統(tǒng)signal(),raise()。3-使用C庫的setjmp()和longjmp().信號處理方法和setjmp、longjmp函數(shù)不調(diào)用析構(gòu)函數(shù),對象不能被正確清理。
4、throw 創(chuàng)建程序所拋出對象的一個拷貝。throw表達(dá)式返回這個對象。try/catch異常處理器可以處理某種異常類型和這種異常類型的派生類。并且為避免再次拷貝異常對象,最好通過引用而不是通過值來捕獲異常。通過引用來捕獲異常,基類異常處理器能夠捕獲派生類異常。
5、catch(...){}可以捕獲任何類型的異常。在異常處理器內(nèi)部catch(){throw;}使用不帶參數(shù)的throw可以重新拋出異常。
6、如果沒有一個異常處理器可以捕獲異常,terminate()會自動被調(diào)用。<exception>中定義.terminate調(diào)用abort(),導(dǎo)致程序不會正常終止函數(shù),全局對象額靜態(tài)對象的析構(gòu)函數(shù)不會執(zhí)行。terminate也會在下面兩個條件下執(zhí)行:局部對象的析構(gòu)函數(shù)拋出異常時,棧正在進(jìn)行清理工作;或者是全局對象或靜態(tài)對象的構(gòu)造函數(shù)或析構(gòu)函數(shù)拋出異常。set_terminate函數(shù)可以設(shè)置自己的terminate函數(shù),自定義的terminator不能有參數(shù),且返回值為void類型。第一次調(diào)用返回默認(rèn)的terminate函數(shù)的指針,這樣可以在需要的時候恢復(fù)原來的terminate。
7、防止資源泄漏,采用方式:1-在構(gòu)造函數(shù)中捕獲異常,用于釋放資源。2-在對象的構(gòu)造函數(shù)中分配資源,并在對象的析構(gòu)函數(shù)中釋放資源。
8、若返回類型為引用,則表示不能返回0.因?yàn)椴荒苡锌找谩?
9、RAII,資源獲得式初始化,是一個封裝類,用于封裝指向分配的對內(nèi)存的指針,使得程序能夠自動釋放這些內(nèi)存。auto_ptr類模板在頭文件<memeroy>中定義。auto_ptr<類>
10、從exception類(定義在頭文件<exception>中)派生自己定義的標(biāo)準(zhǔn)異常類。兩個派生類:logic_error和runtime_error。這兩個類在頭文件<stdexcept>文件中,派生類接受參數(shù)std::string的構(gòu)造函數(shù)。通過exception::what()函數(shù),可以得到保存的消息。因?yàn)閑xception沒有參數(shù)為string的構(gòu)造函數(shù),所以用戶最好從兩個派生類派生自己定義的類。
11、異常規(guī)格說明:int fun () throw(big,small);函數(shù)可能拋出的異常寫在throw之后的括號中。int fun()throw()表示函數(shù)不會拋出任何異常。int fun()表示函數(shù)有可能拋出任何類型的異常。如果異常不在異常規(guī)格說明的異常集中,那么unexcepted會被調(diào)用。默認(rèn)的unexpected調(diào)用terminate函數(shù)。可以使用set_unexpected函數(shù)(頭文件<exception>)使用一個函數(shù)指針作為參數(shù),這個指針指向的函數(shù)沒有參數(shù),而且其返回類型為void。set_unexpected函數(shù)返回unexpected先前的值,所以可以保存這個值,以后使用它。
12、異常規(guī)格說明中包含std::bad_exception 在<exception>中,則unexpected異常會被換成std::bad_exception對象,程序恢復(fù)到函數(shù)被調(diào)用的位置重新開始異常匹配。如果異常規(guī)格說明中不包含std::bad_exception,程序會調(diào)用terminate函數(shù)。VC++中不會調(diào)用set_unexpected()函數(shù)。
13、異常規(guī)格說明與繼承。派生類的異常說明應(yīng)該在結(jié)構(gòu)層次上低于基類的異常說明。即基類的異常說明--》派生出派生類的異常說明。異常規(guī)格說明是為非模板準(zhǔn)備的。
14、operator=應(yīng)遵守6個模式:1-確保程序不給自己賦值,如果是的話跳6。2-給指針數(shù)據(jù)成員分配新內(nèi)存。3-從原有的內(nèi)存區(qū)向新分配的內(nèi)存區(qū)拷貝數(shù)據(jù)。4-釋放原有的內(nèi)存。5-更新對象狀態(tài),也就是把指向分配新堆內(nèi)存地址的指針賦值給指針數(shù)據(jù)成員。6-返回*this。
15、當(dāng)delete對象的時候,對象的析構(gòu)函數(shù)會被調(diào)用。不要在析構(gòu)函數(shù)中拋出異常 。
第二章
1、測試套件框架TestSuit,包含兩個主要的類:Test和Suit。Test類保存測試成功和失敗的次數(shù)??梢詮腡est類派生自己的測試對象。只需要重寫成員函數(shù)run()即可,并用test_()來測試。使用report函數(shù)顯示前面的輸出。
2、Test類有3個虛函數(shù):虛析構(gòu)函數(shù)、reset函數(shù),純虛函數(shù)run;基類設(shè)置虛析構(gòu)函數(shù),表示可以通過基類指針釋放在堆上分配的派生類對象。
3、利用宏處理代碼跟蹤:這兩個宏可以完成調(diào)試器的基本功能,跟蹤代碼執(zhí)行,并顯示表達(dá)式的值。
#define TRACE(ARG) cout<<#ARG<<endl; ARG ? 變種:#define TRACE(ARG) cout<<#ARG"=["<<ARG<<"]"<<endl;
第三章?
1、C++字符串string極大減少了C語言編程中3中最常見的錯誤:1-數(shù)組越界。2-通過未被初始化或被賦以錯誤值的指針來訪問數(shù)組元素。3-在釋放了某一數(shù)組原先所分配的存儲單元后仍保留了懸掛指針。
2、創(chuàng)建string對象:1-創(chuàng)建空string對象。2-將字符串傳給構(gòu)造函數(shù)。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(). 當(dāng)前分配的存儲空間的規(guī)模: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]開始查找,默認(rèn)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找第一個與指定數(shù)值中任一個字符匹配,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),兩個默認(rèn)值,起始位置,刪除的個數(shù)。s.erase()刪除所有。
13、<string>全局函數(shù)getline(in,s).使用s.c_str()可以將string類型轉(zhuǎn)換成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 最主要的目的是防止頭文件被重復(fù)包含與編譯。
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);文件指針相對文件首偏移字節(jié)數(shù)。
11-rewind(fp);將指針移至文件開頭。12-memcpy(newdata,data,sizeof()*count);
3、ostream &os;char fillc=os.fill('0');填充'0',返回先前的填充。os<<setfill(fillc)<<endl;恢復(fù)先前的填充。os<<setw(4)<iomanip>
4、按行輸入:成員函數(shù)get(),成員函數(shù)getline(),全局函數(shù)getline ()。1-2-有三個參數(shù):指向緩沖區(qū)的指針、緩沖區(qū)大小、結(jié)束字符:默認(rèn)'\n',while(in.get(buf,SZ) in.get(); 第一個get讀SZ-1個字符,遇到結(jié)束符。用get()跳過輸入流中的結(jié)束符?;蛘呤褂胕gnore(int N=1,char c=EOF),跳過的字符的數(shù)目,默認(rèn)為1,遇到C字符時,函數(shù)退出,默認(rèn)為EOF。 ? while(in.getline(buf,SZ)在遇到結(jié)束字符的時候,兩個都會在結(jié)果緩沖區(qū)末尾存儲一個0,區(qū)別:當(dāng)遇到結(jié)束符,get停止執(zhí)行,不從輸入流中提取結(jié)束符。再調(diào)用get,會遇到同一個結(jié)束符,函數(shù)將立即返回而不會提取輸入。而getline相反,將從輸入流中提取結(jié)束符,但仍然不會把它存儲到結(jié)果緩沖區(qū)中。get的重載版本:1-int get(),沒有參數(shù),返回int類型的下一個字符.2-get(char &),從流中讀取一個字符放到這個參數(shù)中。3-把流對象存儲到基礎(chǔ)的緩沖區(qū)中。
5、處理流錯誤:ios::badbit,發(fā)生致命錯誤,流不能繼續(xù)使用。ios::eofbit,輸入結(jié)束,ctrl+D. ios::failbit,輸入非法數(shù)據(jù),流可以繼續(xù)使用。ios::goodbit:正常。清空標(biāo)志位:myStream.clear();設(shè)置某個標(biāo)志位,重置另一個標(biāo)志位:myStream.clear(ios::failbit|ios::eofbit);
6、打開剛創(chuàng)建的文件:ofstream out("file.out");ifstream in("file.out");對同一個文件打開讀寫要確定關(guān)閉文件。方法:一、使用大括號,是對象離開作用域調(diào)用析構(gòu)函數(shù),{out}in.二、使用out.close().
7、文件打開模式:ios::in打開輸入文件ios::out打開輸出文件ios::app打開一個僅用于追加的輸出文件ios::ate打開一個已存在的文件,并將文件指針指向文件末尾ios::trunc如果文件存在,截?cái)嗯f文件。ios::binary以二進(jìn)制方式打開文件。回車/換行:0x0D/0x0A
8、流緩沖:streambuf對象將<<右側(cè)對象中的字符輸出到左側(cè)的對象中, ?ifstream in("i.cpp");cout<<in.rdbuf();輸出文件內(nèi)容到標(biāo)準(zhǔn)輸出。rdbuf返回一個指針。
9、ios::beg流的開始位置,ios::cur流的當(dāng)前位置,ios::end流的末端位置,p表示寫指針,g表示讀指針。ostream 調(diào)用tellp,seekp. ?istream 調(diào)用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直接對內(nèi)存而不是對文件和標(biāo)準(zhǔn)輸出設(shè)備進(jìn)行操作。它使用和cin、cout、相同的讀取和格式化函數(shù)來操縱內(nèi)存中的數(shù)據(jù)。寫字符到字符串流,使用ostringstream,從這個流讀取字符,可以使用istringstream。頭文件<sstream>.epsilon()返回在<limits>中定義的常量,表示雙精度數(shù)字的機(jī)器誤差。 istringstream s("47 1.414 this is a test");int i;double f;s>>i>>f; ?ostringstream將字符串插入動態(tài)緩沖區(qū),調(diào)用str()將內(nèi)存中字符串轉(zhuǎn)換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、格式化標(biāo)志:setf()打開標(biāo)志,unsetf()關(guān)閉標(biāo)志。標(biāo)志:ios::skipws 跳過空格 ios::showbase打印整型時指出數(shù)字的基數(shù)(dec/oct/hex)。ios::showpoint顯示浮點(diǎn)值的小數(shù)點(diǎn)。ios::uppercase顯示十六進(jìn)制時,使用大寫。ios::showpos:顯示正數(shù)前面的'+'。ios::unitbuf:單元緩沖區(qū)。立即刷新。cout.setf(ios::showpos)顯示正號cout.unsetf(ios::showpos)關(guān)閉顯示。
13、格式化域:ios::basefield (ios::dec使整型數(shù)值的基數(shù)為10,ios::hex使整型數(shù)值的基數(shù)為16,ios::oct使整型數(shù)值的基數(shù)為8).ios::floatfield(ios::scientific以科學(xué)計(jì)數(shù)的形式顯示浮點(diǎn)數(shù).ios::fixed以固定格式顯示浮點(diǎn)數(shù)。)ios::adjustfield(ios::left使數(shù)值左對齊,填充字符右邊空位。ios::right,ios::internal填充字符放在正負(fù)號和數(shù)值之間正負(fù)號左對齊,數(shù)值右對齊),cout.setf(ios::fixed,ios:floatfield);
14、寬度、填充、精度:int ios::width()返回當(dāng)前寬度,默認(rèn)為0,in ios::width(int n)設(shè)定寬度,返回先前。,int ios::fill()返回當(dāng)前填充字符,默認(rèn)為空格,int ios::fill(int n)設(shè)定填充字符,返回先前,int ios::precision()默認(rèn)精度小數(shù)點(diǎn)后面六位,int ios::precision(int n)設(shè)定精度,返回先前。寬度不會截?cái)嘧址?。寬度只?guī)定最小長度。
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()相當(dāng)于ios::setf(),resetiosflags,相當(dāng)于ios::unsetf(),
setbase(base n),n取值8,10,16,輸出的基數(shù)。setfill(char n)相當(dāng)于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、模板參數(shù):無類型模板參數(shù)template<class T,size_t N> class Stack{
T data[N];
size_t count;
public:
void push(const T& t);
};
實(shí)例化模板時,為參數(shù)N提供一個編譯時常數(shù)Stack<int ,100> myStack;
2、默認(rèn)模板參數(shù):template<class T, size_t N=100> class Stack{};實(shí)例化:Stack<int> stack;
template<class T, class Allocator=allocator<T> > class vector;vector有兩個參數(shù),一個參數(shù)表示它持有的包含對象的類型。另一個參數(shù)表示vector所使用的分配器。
函數(shù)模板不可以使用默認(rèn)的模板參數(shù)。卻能使用模板參數(shù)作為普通函數(shù)的默認(rèn)參數(shù)。
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;}參數(shù)默認(rèn)是T(),int()執(zhí)行零初始化。int a=int();
3、模板類型的模板參數(shù):
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;
}
此時的默認(rèn)參數(shù)需要重新聲明:
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不是創(chuàng)建一個新類型,而是聲明id是一個嵌套類型,然后創(chuàng)建這個類型的對象 i。
class Y{
class id {};
};
創(chuàng)建一個新類型:typedef typename Seq<It>::iterator It;
2-typename代替class
4、<typeinfo> cout<<typeid<T*this>.name(),返回type_info對象。成員模板函數(shù)不能為virtual虛類型。
5、min<>(1,4),表示強(qiáng)制使用模板。<cctype>toupper/tolower有一個參數(shù),<iostream>toupper/tolower有兩個參數(shù)。避免沖突:
1-可以在不包含<iostream>中使用,2-可以使用封裝的函數(shù)模板:template<class charT> charT strTolower(charT c){return tolower(c);}3-可以使用類型轉(zhuǎn)換:
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、模板不是代碼,是產(chǎn)生代碼的指令。防止模板代碼膨脹:一個模板化的Stack容器,用int,int *,char*特化,會生成3個版本的Stack代碼,可以用void* 進(jìn)行完全特化,然后從void*實(shí)現(xiàn)中派生出所有的其他的指針類型。
8、名稱查找問題:編譯器第一階段對模板解析,第二階段模板實(shí)例化。限定名:MyClss::f()/x.f()/p->f() ?關(guān)聯(lián)參數(shù)查找。若名稱是關(guān)聯(lián)的,則它的查找在實(shí)例化進(jìn)行,非限定的關(guān)聯(lián)名稱除外,它是一個普通的名稱查找,它的查找在定義時進(jìn)行,比較早。
9、在類中聲明一個友元函數(shù),就允許一個類的非成員函數(shù)訪問這個類的非公有成員。友元函數(shù)模板必須提前聲明。
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是一個普通函數(shù)
};
10、模板元編程:編譯時編程,在程序開始運(yùn)行前就已經(jīng)完成了計(jì)算。
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關(guān)鍵字。
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;//構(gòu)造函數(shù)初始化,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的數(shù):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>()默認(rèn)構(gòu)造函數(shù)表示文件的結(jié)束
5、size_t n=count_if(a,a+SZ,gt15);產(chǎn)生>15的整數(shù)元素的個數(shù)。int *p=find(a,a+SZ,20)搜索一個序列,直到遇到等于第三個參數(shù)的元素。返回第一次找到的指針位置。
6、函數(shù)對象:它實(shí)現(xiàn)起來像函數(shù)同時保存狀態(tài),使用時卻不用考慮函數(shù)參數(shù)的個數(shù)。這種抽象叫函數(shù)對象。
<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)))
產(chǎn)生標(biāo)準(zhǔn)函數(shù)對象的模板表達(dá)式:類型: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、函數(shù)指針適配器ptr_fun()把一個指向函數(shù)的指針轉(zhuǎn)化成一個函數(shù)對象。
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))算法將序列中每一個元素一次傳遞給第三個參數(shù)指示的函數(shù)對象。mem_fun()使用指向成員的一個指針來作為它的參數(shù)。mem_fun_ref()為一個對象直接調(diào)用成員函數(shù)
#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()要求它調(diào)用的函數(shù)返回一個值。不能使用transform()調(diào)用返回值為void的成員函數(shù),也不能調(diào)用只有一個參數(shù)的for_each函數(shù)
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()); 對區(qū)間每個元素調(diào)用gen(). ? generate_n(back_inserter(v2),7,gen())對gen()調(diào)用7次,將返回值賦給由first開始的7個元素。
12、計(jì)數(shù):count(v.begin(),v.end(), value); ?count_if(v.begin(),v.end(),pred)//pred返回true的個數(shù)
13、操作序列:
copy(v.begin(),v.end(),dest.begin())
copy_backward(v.begin(),v.end(),dest.begin())//以相反的順序復(fù)制元素
reverse(v.begin(),v.end())//倒置原序列范圍的元素
reverse_copy(v.begin(),v.end(),dest.begin())
swap_ranges(v.begin().v.end(),v2.begin())//交換相等大小兩個范圍的內(nèi)容
rotate(first,middle,last)//[first,middle)內(nèi)容移至末尾,[middle,last)元素移至開始
rotate_copy(first,middle,last,dest)
next_permutation(first,last)//排列成后繼的排列
next_permutation(first,last,pred)//重載
pre_permutation(first,last)//排列成前驅(qū)的排列
pre_permutation(first,last,pred)//重載
random_shuffle(first,last)//隨機(jī)重排范圍內(nèi)的元素
random_shuffle(first,last,rand)//重載,使用用戶提供的隨機(jī)函數(shù)重排
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)//第二序列是否出現(xiàn)在第一序列范圍之內(nèi),順序完全一致,返回首先出現(xiàn)的位置
search(first1,last1,first2,last2,pred)//比較的每對元素是否使pred為true.
find_end(first1,last1,first2,last2)//第二序列是否是第一序列的子集,返回最后出現(xiàn)的位置
find_end(first1,last1,first2,last2,pred)//比較的每對元素是否使pred為true.返回最后出現(xiàn)的位置
search_n(first,last,value)//找count個連續(xù)的值,與value相等。
search_n(first,last,value,pred)//與value相等的值傳遞給pred,返回true,否則返回last.
min_element(first,last)//最小值首次出現(xiàn)的位置
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、排序和運(yùn)算
排序:
sort(first,last)//升序
sort(first,last,pred)
stablesort(first,last)//升序,保持相等元素的原始順序
stablesort(first,last,pred)
partial_sort(first,middle,last)//對一定數(shù)量元素排序,放入[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)
運(yùn)算:
在已排序的序列中查找
binary_search(first,last,value)
binary_search(first,last,value,pred)
lower_bound(first,last,value)//第一次出現(xiàn)的位置,若沒有,返回應(yīng)該出現(xiàn)的位置
lower_bound(first,last,value,pred)
upper_bound(first,last,value)//超過value最后出現(xiàn)的位一個置,若沒有,返回應(yīng)該出現(xiàn)的位置
upper_bound(first,last,value,pred)
pair<ForwardIterator1,ForwardIterator2> ? pair在頭文件<utility>中定義
equal_range(first,last,value)//結(jié)合了lower_bound和upper_bound,返回一個指出value在已排序的范圍[first,last)中首次出現(xiàn)和超越最后出現(xiàn)的pair,如果沒有找到,這兩個迭代器都指 //出value在該序列中應(yīng)該出現(xiàn)的位置。
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)
在已排序的序列上進(jìn)行集合運(yùn)算
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、堆運(yùn)算
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)//轉(zhuǎn)化成普通的排列順序,是不穩(wěn)定的排序
sort_heap(first,last,pred)
19、對某一范圍內(nèi)的所有元素進(jìn)行運(yùn)算
UnaryFuntion for_each(first,last,UnaryFuntion f);//對范圍中每個元素應(yīng)用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、數(shù)值算法
<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應(yīng)用f(result,*i)
T inner_product(first1,last1,first2,T init)//init是內(nèi)積的初始值,可能是0或其他值。廣義內(nèi)積。{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是內(nèi)積的初始值。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(雙端隊(duì)列) 都有push_back(),list和deque還有一個push_front(),vector和deque可以使用operator[],但是list不支持
容器適配器:queue、stack、priority_queue
關(guān)聯(lián)式容器: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()//刪除容器中全部內(nèi)容
6、向量:vector 索引和迭代操作速度快,除了在最后一個元素之后插入新元素外,向vector中插入一個對象是不可接受的操作。
? ? 副作用:當(dāng)一個vector與存儲空間用完以后,為維護(hù)其連續(xù)的對象數(shù)組,它必須在另一個地方重新分配大塊新的存儲空間,并把以前已有的對象拷貝到新的 存儲空間中去。
? ? 已分配存儲區(qū)溢出的代價(jià):1-分配一塊新的更大的存儲區(qū)。2-將舊存儲區(qū)中的對象拷貝到新開辟的存儲區(qū)中去,使用拷貝構(gòu)造函數(shù)。3-銷毀舊存儲區(qū)中的所有對象。4-釋放舊存儲區(qū)的內(nèi)存。
? ? 如果vector經(jīng)常被填滿,系統(tǒng)將會為這些拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù)操作的完成付出高昂的代價(jià)。
? ? 為了支持排序和查找等操作,需要有運(yùn)算符operator< 、 operator==。int size=atoi("1000");<stdlib>
? ? 使用vector最有效的條件是:1-在開始時使用reserve()分配了正確數(shù)量的存儲區(qū)。因此vector不再重新分配存儲區(qū)。2-僅僅在序列的后端添加或刪除元素。利用迭代器向vector中間插入或者刪除元素是可能的。
7、雙端隊(duì)列:deque,在序列兩端對元素添加和刪除。允許快速隨機(jī)訪問。支持operator[]
? ? deque允許在序列兩端快速地插入和刪除元素,并且在其擴(kuò)展存儲區(qū)的時候不需要拷貝和銷毀對象的操作。
? ? 1-deque沒有像vector的那種把所有東西保存在一塊連續(xù)的內(nèi)存中的約束。利用多個連續(xù)存儲塊。2-不需要在分配新的存儲區(qū)是復(fù)制并銷毀所包含的對象。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都提供隨機(jī)訪問,使用索引操作符operator[],使用at(),越界則拋出異常。使用at()代價(jià)更高一些。
8、鏈表: list:雙向鏈表數(shù)據(jù)結(jié)構(gòu)。在任何地方快速插入或刪除元素。
list<string> l,l2;
l.reverse()//倒置
l.sort()//排序
swap(*it1,*it2)
reverse(l.begin(),l.end());//起作用
通用的sort()算法僅僅適用于數(shù)組、vector和deque
list<string>::iterator it1,it2;
it1=l.begin();
l.splice(it1,l2)//鏈表l在it1處開始結(jié)合鏈表l2,注意:結(jié)合之后l2是空的。
l.splice(it1,l2,it2)//鏈表l在it1處開始結(jié)合鏈表l2[it2]
l.splice(it1,l2,it2,it3)//鏈表l在it1處開始結(jié)合鏈表l2從it2開始終止在it3.
l2.remove(l2.back());//刪除具有特定值的所有元素
l2.remove(l2.front());
?l.merge(l2);//合并成倆個表,
?l.sort();
?l.unique();//從list中刪除所有相鄰的重復(fù)的對象,唯一的條件就是首先對list進(jìn)行排序。
l.swap(l2)
9、集合:set僅接受每個元素的一個副本,并對元素排序。set是用一個平衡樹數(shù)據(jù)結(jié)構(gòu)來存儲其元素以提供快速的查找。
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一起被歸類為適配器。建立在另一個序列容器的基礎(chǔ)之上。它們將通過調(diào)整某一個序列容器以存儲自己的數(shù)據(jù)。
stack<string> Stack1;//默認(rèn)使用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()獲得等價(jià)的堆棧功能,還擁有vector 的附加功能。
11、隊(duì)列 queue,容器默認(rèn)的模板參數(shù)是deque.
queue<string> que;
if(!que.empty())
{
cout<<que.front();
que.pop();
}
12、優(yōu)先隊(duì)列 priority_queue #include <queue>
當(dāng)向一個優(yōu)先隊(duì)列中用push壓入一個對象時,那個對象根據(jù)一個比較函數(shù)或函數(shù)對象在隊(duì)列中排序。priority_queue確定在用top查看頂部元素時,該元素將是具有最高優(yōu)先級的一個元素。處理完該元素,用pop刪除。
priority_queue<int> pqi;//
pqi.push(i);
while(!pqi.empty())
{
cout<<pqi.top();
pqi.pop();
}
改變優(yōu)先級
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
堆就是一個優(yōu)先隊(duì)列:make_heap(),push_heap(),pop_heap(),priority_queue只是對它的封裝。使用sort_heap之后,再使用make_heap,轉(zhuǎn)換成堆。
13、持有二進(jìn)制位:二進(jìn)制位集合bitset和邏輯向量vector<bool>不同點(diǎn):1-bitset持有固定二進(jìn)制位,vector<bool>動態(tài)擴(kuò)展。2-bitset沒有迭代器,vector<bool>是vector的特化。3-bitset與STL不相似,vector<bool>類似于類STL 容器。
bitset參數(shù)表示二進(jìn)制位的個數(shù):bitset<10>與bitset<20>是兩種不同的類型,不能將它們兩個之間進(jìn)行比較、賦值等操作。從bitset到一個數(shù)的轉(zhuǎn)換用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,不夠在前補(bǔ)0至32位,多了則刪除后面的。
cout<<BS(bits,2)從第二個字符開始,不夠在前補(bǔ)0至32位,多了則刪除后面的。
cout<<BS(bits,2,11)從第二個字符開始連續(xù)11個字符,不夠在前補(bǔ)0至32位,多了則刪除后面的。
cout<<a<<endl;//輸出二進(jìn)制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//從右往左下標(biāo):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的個數(shù)
cout<<a.any()//有1存在?
cout<<a.none()//沒有1存在?
cout<<a.size()//BS 的二進(jìn)制位數(shù)
vector<bool>:是vector模板的特化,
沒有set,reset,只有在vector基礎(chǔ)上加了flip
?ostringstream os;
?copy(vb.begin(), vb.end(),ostream_iterator<bool>(os, ""));
?bitset<10> bs(os.str());
?cout << "Bitset:" << endl << bs << endl;
14、關(guān)聯(lián)式容器 set/map/multiset/multimap 它們將關(guān)鍵字與值關(guān)聯(lián)起來。set可以看成是沒有值的map,它只有關(guān)鍵字。
關(guān)聯(lián)式容器最重要的操作是將對象放進(jìn)容器。在set的情況下要查看該對象是否已在集合中,在map情況下先查看關(guān)鍵字是否已在map中,如果存在,就為關(guān)鍵字設(shè)置關(guān)聯(lián)值。
set<Noisy> s(a,a+SZ);
Noisy n;
s.insert(n);
cout<<s.count(n);//關(guān)鍵字出現(xiàn)的次數(shù):0/1
if(s.find(n)!=s.end())
map<int , Noisy> nm;
for(i=0;i<10;i++){
nm[i];//自動創(chuàng)建對象,如果使用operator[]查找一個值而它又不存在的話,這個map就會創(chuàng)建一個新的關(guān)鍵字-值對。即:如果實(shí)際上想要查詢某個對象并不想創(chuàng)建一個新條目,就必須使用個成員函數(shù)count()或者find().
}
nm.insert(make_pair(47.n))
nm.count(10);//
map<int ,Notify>::iterator it=nm.find(6);//關(guān)鍵字出現(xiàn)的次數(shù):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、通過指針或引用來決定對象運(yùn)行時類型的一種方法是使用運(yùn)行時類型轉(zhuǎn)換。此方法適合把基類指針類型轉(zhuǎn)換為派生類型,也稱向下類型轉(zhuǎn)換。
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提供類型轉(zhuǎn)換檢查。
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<目標(biāo)類型>(操作數(shù)),dynamic_cast要求使用的目標(biāo)對象的類型是多態(tài)的,這就要求該類必須至少有一個虛函數(shù)。轉(zhuǎn)換失敗拋出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獲得動態(tài)類型的名稱。const PolyBase *ppdtypeid(*ppb)
3、類型轉(zhuǎn)換到中間層次類型
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、接口繼承:僅僅在一個派生類接口中加入了成員函數(shù)的聲明。除了析構(gòu)函數(shù)以外,這些聲明都是純虛函數(shù)。
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、實(shí)現(xiàn)繼承:在派生類中實(shí)現(xiàn)所有的 細(xì)節(jié)。
protected類型需要一個友元或派生類來使用它?;惖奈鰳?gòu)函數(shù)是虛函數(shù)。可以保證派生類的對象正確的銷毀。
3、重復(fù)子對象
當(dāng)從某個基類繼承時,可以在派生類中得到那個基類的所有數(shù)據(jù)成員的副本。
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
*/ ///:~
如果有多個基類,若果這些基類依次有一個共同的基類,那么將得到頂層基類的兩個副本,
如果有多個基類,派生類向上類型轉(zhuǎn)換會出現(xiàn)二義性。
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、虛基類:消除向上類型轉(zhuǎn)換時二義性的問題。
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*的結(jié)果總是確定指向完整對象的地址。
5、含有虛基類的子對象的初始化順序
1-所有虛基類子對象,按照他們在了定義中出現(xiàn)的位置,從上到下,從左到右初始化。
2-然后非虛基類按通常順序初始化。
3-所有的成員對象按聲明的順序初始化。
4-完整的對象的構(gòu)造函數(shù)執(zhí)行。
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、名字查找問題的二義性:
類繼承了兩個同名的函數(shù),沒有方法在他們之間選擇:
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
} ///:~
消除二義性調(diào)用的方法,是以基類名來限定函數(shù)的調(diào)用。
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()
} ///:~
名稱優(yōu)勢:
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占優(yōu)勢。
7、避免使用多繼承
關(guān)心兩個問題:1-是否需要通過新類來顯示兩個類的公共接口。2-需要向上類型轉(zhuǎn)換成為倆個類型嗎?
第十章 設(shè)計(jì)模式
動機(jī):為了使變化的事物與不變的事物分離開。
1、模式分類
創(chuàng)建型:Creational:用于怎樣創(chuàng)建一個對象,隔離對象創(chuàng)建的細(xì)節(jié),代碼不依賴于對象是什么類型,因此在增加一種新的對象類型時不需要改變代碼。Sington、Factory、Builder模式。
單件模式、工廠模式、構(gòu)建器模式。
結(jié)構(gòu)型:Structural:影響對象之間的連接方式,確保系統(tǒng)的變化不需要改變對象間的連接。Proxy、Adapter模式。代理模式和適配器模式。
行為型:Behavioral:在程序中處理具有特定操作類型的對象。這些對象封裝要執(zhí)行的操作過程。如:解釋一種語言、實(shí)踐一個請求、遍歷一個序列、實(shí)現(xiàn)一個算法等。
Command、Template Method、State、Strategy、Chain of Responsibility、Observer、Multiple Dispatching、Vistor模式
命令模式、模板方法模式、狀態(tài)模式、策略模式、職責(zé)鏈模式、觀察者模式、多派遣模式、訪問者模式。
2、創(chuàng)建型:單件模式:Singleton ? 它是允許一個類有且僅有一個實(shí)例的方法。
#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-創(chuàng)建單件模式的關(guān)鍵是防止客戶程序員獲得任何控制其對象生存期的權(quán)利。聲明所有構(gòu)造函數(shù)為私有??截悩?gòu)造函數(shù)和賦值函數(shù)被聲明為私有。
2-可以采用靜態(tài)創(chuàng)建對象,也可以等待,直到客戶程序員提出要求再根據(jù)要求進(jìn)行創(chuàng)建。
3-返回引用而不是返回指針,防止用戶不小心刪除指針。
4-任何情況下,對象應(yīng)該私有保存。
單件的變體:將在一個成員函數(shù)內(nèi)部的靜態(tài)對象的創(chuàng)建與單件類結(jié)合在一起。
一個類中的任何static靜態(tài)成員對象都表示一個單件:有且僅有一個對象被創(chuàng)建。
如果一個靜態(tài)對象依賴于另一個對象,靜態(tài)對象的初始化順序是很重要的。
在函數(shù)中定義一個靜態(tài)對象來控制初始化順序,直到該函數(shù)第一次被調(diào)用時才進(jìn)行初始化。如果函數(shù)返回一個靜態(tài)對象的引用,就可以達(dá)到單件的效果。
上面程序修改如下:
#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個步驟產(chǎn)生一個單件:1-聲明其構(gòu)造函數(shù)為私有或保護(hù)的。2-聲明類Singleton<MyClass>為友元。3-從SIngleton<MyClass>派生出MyClass.步驟3:這是對模板Singleton中模板參數(shù)的靜態(tài)依賴。類Singleton<MyClass>能被編譯器實(shí)例化,因?yàn)樗灰蕾嘙yClass的大小。
#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):選擇操作
特點(diǎn):消除代碼間的耦合,消除被調(diào)用函數(shù)的選擇與那個函數(shù)被調(diào)用位置之間的聯(lián)系。
主要特點(diǎn):允許向一個函數(shù)或者對象傳遞一個想要的動作。
命令模式就是一個函數(shù)對象:一個作為對象的函數(shù),通過將函數(shù)封裝為對象,就能夠以參數(shù)的形式傳遞給其他函數(shù)或者對象。
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、結(jié)構(gòu)型:代理模式(Proxy):作為其他對象的前端
代理模式和狀態(tài)模式都提供一個代理類,代碼與代理類打交道,而作實(shí)際工作的類隱藏在代理類背后。當(dāng)調(diào)用代理類中的一個函數(shù)時,代理類轉(zhuǎn)而去調(diào)用實(shí)現(xiàn)類中相應(yīng)的函數(shù)。從結(jié)構(gòu)上看,代理模式是狀態(tài)模式的一個特例。
基本思想:代理類派生自一個基類,由平行地派生自同一個基類的一個或多個類提供實(shí)際的實(shí)現(xiàn)。
當(dāng)一個代理對象被創(chuàng)建的時候,一個實(shí)現(xiàn)對象就分配給了它,代理對象就將函數(shù)調(diào)用發(fā)給實(shí)現(xiàn)對象。
從結(jié)構(gòu)上看,代理模式和狀態(tài)模式的區(qū)別:代理模式只有一個實(shí)現(xiàn)類,而狀態(tài)模式有多個實(shí)現(xiàn)。應(yīng)用也不同:代理模式控制對其實(shí)現(xiàn)類的訪問。而狀態(tài)模式動態(tài)的改變其實(shí)現(xiàn)類。
#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、行為型:狀態(tài)模式(State):改變對象的行為
狀態(tài)模式產(chǎn)生一個改變其類的對象,當(dāng)發(fā)現(xiàn)在大多數(shù)或者所有函數(shù)中都存在有條件的代碼時,這種模式很有用。和代理模式一樣,狀態(tài)模式通過一個前端對象來使用后端實(shí)現(xiàn)對象。
測試一個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變量,使用狀態(tài)對象,是代碼簡化。
#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、結(jié)構(gòu)型:適配器模式(Adapter)
接受一種類型并且提供一個對其他類型的接口。
創(chuàng)建適配器,接受FibonacciGenerator并產(chǎn)生一個供STL算法使用的迭代器。
class FibonacciGenerator {//斐波那契數(shù)列
? 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)
模板方法模式的一個重要特征是它的定義在基類中,并且不能改動。模板方法模式就是堅(jiān)持相同的代碼,它調(diào)用基類的不同函數(shù)來驅(qū)動程序運(yùn)行。
驅(qū)動程序運(yùn)行的引擎是模板方法模式,這個引擎是主要的事件環(huán),客戶程序員只需提供customize1()、customize2()的定義,便可以令應(yīng)用程序運(yùn)行。
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):運(yùn)行時選擇算法
將變化的代碼從“堅(jiān)持相同代碼”中分開。策略即:使用多種方法來解決某個問題。
好處:在程序運(yùn)行時可以加入變化的代碼。
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、行為型:職責(zé)鏈模式(Chain of Responsibility):嘗試采用一系列策略模式,本質(zhì):嘗試多個解決方法直到找到一個起作用的方法。
職責(zé)鏈可看做是使用策略對象的遞歸。在職責(zé)鏈中,一個函數(shù)調(diào)用自身,調(diào)用函數(shù)的一個不同實(shí)現(xiàn),如此反復(fù)直至達(dá)到某個終止條件,這個終止套件或者是已到達(dá)策略鏈的地底部或者是找到一個成功的策略。職責(zé)鏈實(shí)際上是一個鏈表,動態(tài)創(chuàng)建。
使用自動遞歸搜索鏈中每個策略的機(jī)制,職責(zé)鏈模式自動找到一個解決方法。
#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、創(chuàng)建型:工廠模式(Factory):封裝對象的創(chuàng)建。
將創(chuàng)建對象的代碼轉(zhuǎn)到這個工廠中執(zhí)行,那么在增加新對象時所做的全部工作就是只需要修改工廠。
實(shí)現(xiàn)工廠模式的一種方法就是在基類中定義一個靜態(tài)成員函數(shù)。
#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);
} ///:~
多態(tài)工廠:使用不同類的工廠派生自基本類型的工廠。
工廠模式是多態(tài)工廠的一個特例。
#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
抽象工廠:使用若干工廠方法模式,每個工廠方法模式創(chuàng)建一個不同類型的對象。
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 */ ///:~
虛函數(shù)的思想就是發(fā)送一個消息給對象,讓對象確定要做正確的事情。
11、創(chuàng)建型:構(gòu)建器模式(Builder)
目標(biāo):將對象的創(chuàng)建與它的表示法分開。構(gòu)建器模式和抽象工廠模式主要的區(qū)別就是,構(gòu)建器模式一步步創(chuàng)建對象,
功能:將部件組合成為一個完整的產(chǎn)品的算法和部件本身分開,這樣就允許通過一個共同借款的不同實(shí)現(xiàn)來為不同的產(chǎn)品提供不同的算法。
12、行為型:觀察者模式(Observer)
解決一個常見問題:當(dāng)某些其他對象改變狀態(tài)時,應(yīng)該如何處理。
在觀察著模式中有兩個變化的事件,正在進(jìn)行觀察的對象的數(shù)量和更新發(fā)生的方式。即觀察著模式允許修改這二者而不影響周圍的其他代碼。
#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只有一個成員函數(shù):update()接口類。當(dāng)正在被觀察的對象認(rèn)為到了更新其所有觀察者的時機(jī)時,它將調(diào)用此函數(shù)。它允許被觀察者的對象傳遞引起更新操作的對象和任何額外的信息。
#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)
好處:在調(diào)用的時候能夠以簡潔的句法表達(dá)方式達(dá)到預(yù)期的效果。
多態(tài)只能通過虛函數(shù)調(diào)用來實(shí)現(xiàn),要發(fā)生多重派遣,必須有一個虛函數(shù)調(diào)用以確定每個未知的類型。
#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函數(shù)開始雙重派遣。函數(shù)compete調(diào)用eval執(zhí)行第二次派遣。
14、行為型:訪問者模式(Visitor)
目標(biāo):將類繼承層次結(jié)構(gòu)上的操作與這個層次結(jié)構(gòu)本身分開。訪問者模式建立在雙重派遣方案之上。訪問者模式允許創(chuàng)建一個獨(dú)立的類層次結(jié)構(gòu)Visitor而有效的對主類的借口進(jìn)行擴(kuò)展。
#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是主層次結(jié)構(gòu),Flower的各個子類通過函數(shù)accept()得到一個Visitor,Flower主層次結(jié)構(gòu)除了函數(shù)accept沒有別的操作,因此Flower層次結(jié)構(gòu)的所有功能都將包含在Visitor層次結(jié)構(gòu)中。每個Flower中的accept函數(shù)開始一個雙重派遣。第一次派遣決定了Flower類型,第二次派遣決定了Visitor類型?
第十一章
1、進(jìn)程是在其自己的地址空間運(yùn)行的自含式程序。線程是進(jìn)程內(nèi)的單一連續(xù)的控制流。因此一個進(jìn)程可以有多個并發(fā)執(zhí)行的線程。線程運(yùn)行在一個進(jìn)程內(nèi),所以它們共享內(nèi)存和其他資源。
2、防止兩個線程在臨界區(qū)訪問同一資源,加鎖,互斥。 在進(jìn)入臨界區(qū)之前獲得互斥鎖,在臨界區(qū)的終點(diǎn)釋放。
3、原子操作:1-返回int型變量。2-原子操作不能被線程處理機(jī)制中斷。3-對int型變量增1操作也是原子操作。
4、線程狀態(tài):1-新建狀態(tài)。2-可運(yùn)行狀態(tài)。3-阻塞狀態(tài)。4-死亡狀態(tài)。
5、變?yōu)樽枞麪顟B(tài):原因:1-調(diào)用sleep()使線程處于休眠狀態(tài)。2-已經(jīng)使用wait()掛起了該線程的運(yùn)行,在得到signal()或broadcast()消息之前,它不會變?yōu)榭蓤?zhí)行狀態(tài)。3-線程正在等待某個I/O操作完成。4-線程正在嘗試進(jìn)入一段被一個互斥鎖保護(hù)的代碼塊。
6、除了I/O操作,一個任務(wù)可以從任何阻塞操作中中斷出來。
7、進(jìn)程間協(xié)作,通過互斥鎖來同步兩個任務(wù)的行為,來阻止一個任務(wù)干擾另一個任務(wù)的資源。
8、死鎖發(fā)生的條件:1-互斥。線程使用的資源至少有一個必須是不可共享的。2-至少有一個進(jìn)程必須持有某一種資源。并且同時等待獲得正在被另外的進(jìn)程所持有的資源。3、不能以搶占的方式剝奪一個進(jìn)程的資源。4、出現(xiàn)一個循環(huán)等待。一個進(jìn)程等待另外的進(jìn)程所持有的資源,而這個被等待的進(jìn)程又等待另一個進(jìn)程所持有的資源。。。
破壞死鎖的最容易的方法是破壞4.
9、5個哲學(xué)家就餐問題:每個哲學(xué)家以特定的順序拿筷子:先右后左。進(jìn)入循環(huán)等待。解決方法:最后一個哲學(xué)家初始化為:先嘗試拿左邊的筷子,再拿右邊的筷子。
10、線程的優(yōu)點(diǎn):提供輕量級(100條指令)的執(zhí)行語境切換,而非重量級(上千條指令)進(jìn)程語境切換。進(jìn)程中所有的線程共享同一內(nèi)存空間。一個輕量級的語境切換只改變了程序執(zhí)行的先后順序和局部變量。進(jìn)程改變-重量級語境切換-必須調(diào)換所有內(nèi)存空間。
總結(jié)
以上是生活随笔為你收集整理的C ++ 编程思想(卷二) 笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: openldap schema
- 下一篇: Centos 安装 OpenLDAP