某C++神作,就100句話而已

  • 2020 年 11 月 17 日
  • 筆記
  • 假設p是指針,當delete p;時,後面一定要p=NULL將p指向空

  • cin cout cerr 都是iostream類型的對象。cout<<“hello world”<<endl; 其中cout是左操作數對象,<<是操作符,作用是將右操作數寫到左操作數對象,”hello world”是右操作數,前面半句話的意思是將hello world寫入cout對象。同理,<<endl是將endl寫入cout,endl表示刷新緩衝區並換行。

  • std::cout ::是作用域操作符,表示std名空間下的cout,用來區別其它名空間同名變數。

  • 注釋不能嵌套:/* /*…*/ */ 是錯誤的

  • 表示整數、字元和布爾值的算術類型合稱為整形。區分類型是因為只有知道某地址值的類型,才能知道需要多少位表示這個變數和如何解釋這些位。

  • 整形賦值超出取值範圍,會被賦值數對該類型數值數目取模後的值。

  • long類型運行時代價遠高於int類型。以0開頭的字面值常量表示八進位、以0x開頭的表示十六進位。任何字元可以表示為 \ooo【ooo表示一個八進位數】

  • 對象是記憶體中具有類型的區域。初始化不是賦值,初始化是創建並賦值。定義在函數體外的內置變數自動初始化成0,定義在函數體內的內置變數不進行自動初始化,類類型(string)調用默認構造函數初始化。

  • const把一個對象轉換成一個常量【const int bufSize = 512】。 全局變數加const作用域只在本文件。再加extern可在整個程式訪問。非const變數默認為extern。

  • 引用初始化後始終綁定到初始化的對象,不能改變【引用本身不佔存儲單元】。const對象必須由const引用指向【避免一個能修改,一個不能修改,既對象本身和代表其的引用必須同時為const】。普通引用不能初始化為常量,const引用可以。

  • typedef用來定義類型的同義詞。

  • 頭文件用於聲明,不是定義,因而可以出現多次。定義的語句不應該放在頭文件里,出現兩次會導致多重定義鏈接錯誤。例外是頭文件可以定義類,還有值在編譯時就已經知道的const對象,還有inline函數。變數是聲明還是定義看是否有extern,但不是絕對的,函數就看有無大括弧{}

  • 兩個迭代器指向同一個元素就相等【==】,否則不等。任何改變vector長度的操作都會使已存在的迭代器失效。difference_type存儲迭代器間距離。

  • 設計良好的程式只有在強調速度時才在類實現的內部使用數組和指針。數組下標的正確類型是size_t。

  • 預處理器變數NULL在編譯時會被數值0替換。指針做減法操作得到的是ptrdiff_t類型。指針p – 2 等效p[-2]。

  • 定義的多個變數具有相同的類型,就可以在for循環的初始化語句中同時定義他們。for(int a, b, c …)

  • C++強制要求指向const對象的指針也必須具有const特性,可以把非const對象地址賦給const指針。

  • const指針:int *const cur = &cuss; 指向int型變數的指針,並且本身不能修改。

  • C風格字元串:const char *cp = “some value”; strlen(用於計算c風格字元串字元個數,不包括串最後的’\0′)

  • 動態數組:int *p = new int[任意表達式,變數等] delete [] p;

  • new/delete是操作符,不但控制記憶體而且執行構造函數和析構函數,malloc/free是標準庫函數,不在編譯器控制許可權內,不能執行構造和析構。

  • 使用數組初始化vector:int int_arr[arr_size] = {0,1,2,3}; vector ivec(int_arr, int_arr+arr_size);

  • int ival; int *pval; ival = pval = 0; 錯誤,pval = 0 返回的是指針,無法賦值給int。

  • ++i i++ 前置時返回自增後的值,後置時返回值後自增。前置性能好於後置。

  • 逗號表達式的結果是其最右邊表達式的值。

  • if(ia[index++]<ia[index])這個表達式沒有明確的計算順序。除了 && || ?::外其他操作數沒有規定計算順序。不應該使用這種表達式,結果無法確定。

  • int val = 3.24+3;表達式先轉換為高精度,再轉換為左值類型。int *ip; ip=0;隱式轉換0為空指針。

  • 包含signed和unsigned int的表達式會被轉換成unsigned,如果為負數會有問題。

  • 數組名用做sizeof或取地址&的操作數時不被當做指針。sizeof計算棧中分配大小,靜態變數在全局數據區不計算在內。

  • const_cast添加或刪除const特性。

  • 空語句: ;

  • switch case break的判斷表達式必須為整數值。case從匹配的開始執行直到結束,而不是只執行匹配的。

  • do{此處定義的變數循環條件中不可見}while(…)

  • throw 類型 每一個標準庫異常類都有what()函數返回C風格用戶輸入的字元串。如果不存在catch語句,程式默認執行terminate的標準庫函數。

  • 預處理器定義的調試用的常量:__FILE__ __LINE__ __TIME__ __DATE__【列印時間和日期很常用】

  • assert宏用來檢查不可能發生的條件。

  • 函數實參如果和定義類型不一致,但可被轉換成定義類型,那麼也可以使用。

  • 如果需要保護指針指向的值,形參需要定義為指向const的指針。應將不修改實參的形參定義為const引用,好處是可以傳遞字元串字面值(和產生右值的表達式),非const引用反而不靈活。

  • 如果形參是引用,那麼他只是實參的別名。int *&v v是引用,是某個指向int的指針的別名。

  • fun(int*) fun(int[]) fun(int[10])等價,但10其實沒有任何用處。如果定義為fun(int (&arr)[10]),此時會檢查參數是否有10個。

  • C風格字元串以NULL結尾是為了標識結束防止越界

  • 含有可變形參的函數:fun(parm_list, …)與省略符對應的實參暫停類型檢查。

  • 返回值為viod的函數只能使用return;不能return expression。return;也只能用於返回值為void的函數。

  • 靜態變數只在初次調用時初始化,static size_t ctr=0隻執行一次。

  • 內聯函數避免函數調用的開銷:編譯時展開為函數體中的表達式,免去函數調用的暫存器保存恢復、複製實參跳轉等。

  • 內聯函數定義在頭文件。編譯器將類內定義的成員函數當做內聯函數。

  • 每個成員函數都有一個隱含的this指針。假設有成員函數bool same_isbn(..) const 最後的const改變了隱含的this形參的類型,這種成員函數叫常量成員函數,無法修改對象本身。const的對象,指針引用只能調用常量成員函數。

  • 沒有前綴的成員都被假定為this在調用。

  • 默認構造函數按變數初始化規則初始化類中所有成員【內置類型作為局部變數時不初始化】。

  • 指向函數的指針:函數類型由返回值和形參決定,與函數名無關。函數名本身就是指針。fun&fun Fcn pf=add pf(1,2)(*pf)(1,2)

  • 函數的形參可以是指向函數的指針:FUN( bool(string&, string&) ) 或 FUN( bool (*)(string&, string&) )。FUN是函數名,FUN(這裡都是形參)

  • iostream定義讀寫控制窗口的類;fstream定義讀寫已命名文件的類;sstream定義的類型用於讀寫記憶體中的string對象。前面加上w支援wchar_t類型。

  • 流的狀態可以由bad,fail,eof,good函數獲得,cin.fail()。

  • 每一個流都關聯一個緩衝區,崩潰的程式不會自動刷新緩衝區,如果用輸出調試程式,確保每次輸出都flush或endl。tie函數可將istream和ostream綁一起,輸入前首先會刷新輸出。

  • fstream 既要定義對象又要捆綁文件【open或初始化時】。如果想用一個文件流對象讀取多個文件,必須close()並clear()。所有流都可以用<<操作符。

  • 設置或清除多個二進位位狀態:可以多次調用setstate,clear;可以用位或操作符在一次調用中傳遞多個狀態的值。A|B生成了一個值,其對應於A和B的位都打開了,設置為1,其他都是0.

  • 引用不支援一般意義的賦值運算,沒有容器的元素是引用。容器的容器< <之間必須有空格否則會被認為是<<移位操作符。

  • vector deque支援通過元素的位置實現隨機訪問,所以迭代器可以實現算術和關係運算。list容器的迭代器不支援算術運算(加減法iter+n,iter1+iter2),也不支援關係運算(<= < >= >【是元素的比較,類似於string】),只支援++ — == !=。

  • 由容器定義的類型:size_type iterator value_type reference…

  • list deque提供了push_front()。容器元素都是副本。insert push可能導致迭代器失效,當編寫循環將元素插入到vector deque時,必須更新迭代器。size()返回個數,empty()返回布爾值。

  • 如果容器c為空,c.front() c.back()操作未定義!c[n]和c.at(n)只適用於vector deque,n<0或n>=c.size()操作未定義【c.at(n)會拋out_of_range】。

  • 容器操作函數find(begin, end, val) 返回值是迭代器,沒找到返回end。

  • 容器類型和元素類型都相同,可以用賦值vec1=vec2。容器類型不同或元素類型不同,但是兼容可以用assign函數來賦值。

  • vector容器中的元素以連續的方式存放【動態數組】。有預先分配策略,需要重新分配時加倍當前容量。capacity函數獲取目前能夠存儲的元素總數,reserve函數設置capacity。

  • string中的字元也是連續存儲的,也有迭代器string::iterator。string類將string::npos定義為保證大於任何有效下標的值。

  • 本質上,適配器是使一事物的行為類似於另一事物的行為的一種機制。stack queue priority_queue

  • pair類型:pair<T1, T2> p1;p1.first p1.second 。makepair函數可以創建pair對象。vector<pair<int, int> >如果需要多個pair可以放在一個vector中。

  • set中元素不重複,相當於只有鍵沒有值。map的函數大部分都有對應的。

  • 關聯容器:容器元素根據鍵的次序排列。

  • map可以理解為關聯數組,鍵就是下標。

  • map可以用迭代器遍歷,按鍵排序。使用map的insert函數可以避免使用下標操作的副作用:不必要的初始化【如果key已經在map中則map保持不變,避免了初始化】

  • 帶有pair形參的insert版本返回一個迭代器和一個bool值的pair對象。map.count(k)返回k出現的次數。map.find(k)若k存在返回迭代器。map的erase返回void。

  • multimap相同鍵對應的元素必定相鄰存放。multimap.lower_bound(k)指向鍵不小於k的第一個元素,upper_bound(k)。equal_range(k)返回pair代表上下限。

  • 泛型演算法:find函數基於迭代器,不同容器可使用相同find。演算法從不添加和刪除容器元素。it=find_first_of(it,…)可用於多種容器。

  • accumulate(..)累加 fill寫入元素 back_insert插入迭代器能達到push_back的效果 copy replace_copy sort unique count_if 謂詞是檢測函數。

  • 流迭代器:訪問特定類型的輸入 istream_iterator cin_it(cin) 反向迭代器:reverse_iterator

  • const_iterator用於指定範圍的迭代器必要類型一致。容器返回的迭代器是否const取決於容器元素是否const。

  • map set list提供的是雙向迭代器。string vector deque提供的是隨機訪問迭代器【sort函數需要隨機迭代器】。istream_iterator是輸入迭代器,ostream_iterator是輸出迭代器。

  • 對於list對象應該優先使用list容器特有的成員版本【能添加刪除元素】,而不是泛型演算法。

  • 簡單說,類就是定義了一個新的類型和一個新的作用域。成員訪問級別默認私有。在聲明和定義處指定inline都是合法的。類的前向聲明一般用來編寫相互依賴的類。類定義以分號結束,之後可以跟對象列表。

  • mytye.func1().func2()想要這種形式,就必須返回*this的引用才能調用func2。成員函數是否為const等同於形參this是否const,所以可以重載。mutable用來聲明數據成員可以修改【突破各種const的限制】。

  • 使用類外全局作用域的變數可以::var來獲得。

  • 類中的const成員必須在初始化列表中初始化,無法再構造函數體內賦值。初始化const或引用類型或沒有默認構造函數的類類型數據成員的唯一機會是構造函數的初始化列表【冒號開始,逗號分隔】。初始化順序由定義順序決定,而不是初始化列表順序。

  • 友元:將非公有成員的訪問權授予指定的類或函數。friend在類定義內部。友元引入的類名和函數(定義或聲明)可以像預先聲明的一樣使用。

  • static成員函數沒有this形參,可直接訪問類的static成員,不能使用非static成員。

  • 靜態數據成員屬於一個類,而不屬於類的各個對象。靜態成員函數在所有對象建立之前或刪除之後仍然使用。

  • 初始化時是否調用複製構造函數取決於是否有=【拷貝構造函數,複製也叫拷貝構造函數是用同一個類的一個對象初始化另一個對象,普通構造函數是用各種參數初始化一個類的對象】。構造函數如果是explicit必須嚴格按照定義使用構造函數,否則可以存在隱式轉換。

  • 非引用形參將複製實參值,非引用return將複製return的東西。即使定義了其他構造函數,也會合成複製構造函數【能夠複製類中的數組】。類成員有指針一般需要顯示定義複製構造函數。

  • 聲明而不定義成員函數是合法的,但是使用將導致鏈接失敗。將複製構造函數聲明為private可防止複製。定義了複製構造函數,也必須定義默認構造函數。

  • 重載賦值操作符=,隱含的第一個參數this。複製構造函數、賦值操作符、顯示析構函數【虛空不算】一般同時出現。合成析構函數並不刪除指針成員指向的對象。即使編寫了自己的析構函數,合成析構函數仍然運行。

  • 默認構造函數不全,會調成員的默認構造函數,複製構造函數不全就不行了。

  • 使用計數是管理智慧指針類的通用技術。

  • 重載操作符:保留字operator後面接需要定義的操作符符號,返回類型和參數表和其它函數一樣。只能重載已有的操作符,只針對類類型,最好重載原本對類類型無意義的操作符。

  • 使用演算法sort等時會假定一些操作符(<)存在,此時要為類型定義重載操作符。重載操作符如果是成員函數,左操作數必須是該類的對象【一定是this】。

  • 用函數或類操作某個類的數據可設置其為友元。== <的邏輯定義如果不一致,不定義<比較好。()是調用操作符,有這個的類稱為函數對象,行為類似函數。函數對象作為演算法實參,比函數更靈活。標準庫中有幾個函數對象。

  • 函數對象的函數適配器:綁定器 bind1st將給定值綁定到二元對象函數第一個實參 bind2nd 第二個實參。 求反器 not1 not2 count_if find_if

  • 轉換操作符:operator type() type表示內置類型名,類類型名或別名。【operator int(); //重載類型轉換操作符,可以做到int i; Integer it; i = it; //it直接轉為int類型,然後賦值給i 例如:Integer::operator int() {return data;data是Integer的私有成員}】

  • virtual函數是基類希望派生類重新定義的函數,希望派生類繼承的函數不能為虛函數。根類一般要定義虛析構函數。

  • 派生類只能通過派生類對象訪問protected成員,不能用基類對象訪問。基類定義為virtual就一直為虛函數,派生類寫不寫virtual都是虛函數。用做基類的類必須是已定義的。

  • 存在虛函數+指針或引用==產生多態。非虛函數編譯時就按指針或引用或對象類型確定。可以使用域操作符強制調用基類虛函數【虛中調虛】。基類虛函數和派生類的默認實參要一致。

  • 派生類繼承基類的訪問控制標號【何種方式繼承】無論是什麼,不影響派生類使用基類成員,但影響使用派生類的用戶訪問基類成員。類使用介面繼承還是實現繼承對派生類用戶具有重要含義。

  • 友元關係不繼承。

  • 派生類指針可自動轉換到基類指針,反之不行。如果知道基類到派生類的轉換【這種轉換是基類地址賦給派生類指針】是安全的【就是說心裡清楚基類指針指向的確實是派生類】,可以使用static_cast強制編譯器進行轉換。dynamic_cast是在運行時進行檢查。

  • 構造函數無法繼承,派生類構造數還要初始化基類【否則只能用合成構造函數初始化】。初始化列表和初始化的順序無關。只能初始化直接基類。

  • 賦值操作符必須防止自身複製【賦值之前會先釋放自身的內容,萬一是自己, 那不就丟失了】。派生類析構函數不負責清除基類成員,每個析構函數只負責清除自己成員。派生類指針的靜態類型和動態類型不一致時【基類指針指向派生類是時】,為保證刪除指針調用合適的析構函數【多態】,基類析構必須為virtual。

  • 構造函數是對象動態類型確定之前運行的,不需要定義為virtual。

  • 引用、對象、指針的靜態類型決定了能夠完成的行為,動態類型有多的功能也無法使用。派生類應避免與基類成員名字衝突。局部作用域中聲明的函數不會重載全局域的函數。派生類定義的函數也不重載基類函數【想重載要麼不定義,要麼全定義】。using作用域。

  • 純虛函數抽象類無法創建對象 派生類對象複製到基類時派生類對象將被切掉【而指針和引用不會】。

  • 對象不支援動態綁定,指針和引用支援但使用起來麻煩,解決方法是定義包裝類或句柄類【提供到其它類介面的類】。像使用指針一樣使用句柄而不用管理它指向的對象。類似智慧指針的方法建立指針句柄。

  • 關聯容器的構造函數是我們能夠提供比較函數的名字:std::multiset<Sales_item, Comp【比較器】> items(compare【比較函數】);

  • template <typename T>模板定義以關鍵字template開始【舊程式中可能用class】,後接模板形參表,模板形參表是由尖括弧擴住的一個或多個模板形參的列表,以逗號分隔。表中可以有非類型形參,實例化時綁定值。

  • 通過在成員前面加上typename告訴編譯器將成員當做類型。泛型程式碼兩個原則:1.模板形參是const引用 2.函數體中只用<比較

  • 模板形參數量自由,可以設定返回值為一個形參。顯示提供實參:long a=sun<long>(i, lng)

  • export關鍵字能夠指明給定的定義可能會需要在其他文件中產生實例化。非類型形參的模板實參:template<int hi, int wid> 實例化時必須是常量表達式 Screen<24,80>

  • 模板中的友元表示任何實例可以訪問任何實例。模板類中可以有模板類成員。

  • 模板類中的static成員由同一實例化的對象共享,但不同模板形參的實例化對象間不共享。

  • 模板特化:template<> 模板名<模板形參>函數形參表 函數體 特化類 也可以只特化類中某個成員 部分特化:多個模板形參,特化某個形參【編譯器會優先選擇特化的】。匹配同樣好時,非模板版本優先。