第一章 開始
類型:程序所處理的數據都保存在變量中,而每個變量都有自己的類型
內置類型:語言自身定義的類型(而形如string等類型都是標准庫定義的)
main的返回值:0表示成功,非0指出錯誤類型
從命令行運行編譯器
術語表:緩沖區、cerr、clog、表達式
第一部分 C++基礎
第二章 變量和基本類型
幾種字符類型:char 、wchar_t 、char16_t 、char32_t
內置類型的機器實現:內置類型如何在內存存放
將負數轉換為無符號類型:結果為無符號數的模加上這個負數
字面值常量:每個字面值常量都對應一種數據類型、字符串字面值(實際是由常量字符構成的數組),可以指定字面值的類型
轉義序列:回車\r、換行\n
對象:指一塊能存儲數據並具有某種類型的內存空間
初始化:列表初始化、默認初始化
變量聲明和定義的關系:分離式編譯、extern
復合類型:基於其他類型定義的類型
聲明符:聲明語句int &r;中,&r為聲明符,聲明符命名了一個變量,也指定該變量為與基本數據類型(此例為int)有關的某種類型
引用&引用類型:我們稱r為引用或引用類型
指針:*p為聲明符,p是變量名,我們稱p為指針或指針變量
const限定符:常量引用(對常量的引用)、可以將一個常量引用綁定到變量、字面值、表達式(因為不允許通過該引用修改這些對象)
頂/底層const:執行對象拷貝時的限制
constexpr:聲明常量
decltype類型指示符:返回表達式的類型
編寫自己的頭文件:頭文件通常包含那些只能定義一次的實體,如類、const、constexpr變量
預處理變量:#ifdef、#ifndef、#endif
術語表:常量表達式、頭文件保護符、未定義、void*
第三章 字符串、向量和數組
標准庫類型string
string::size_type類型:string的size函數返回的是一個string::size_type類型的值;string類及其他大多數標准庫類型都定義了幾種配套的類型,體現了標准庫類型與機器無關的特性,類型size_type即是其中的一種,通過域操作符來表明名字size_type是在類string中定義的、
處理string對象中的字符:cctyoe頭文件中的函數
迭代器:使迭代器失效的操作
數組:數組的引用,數組的下標類型為size_t,數組名和指針
標准庫函數begin和end
c_str函數:返回一個C風格的字符串,返回結果是一個指針,該指針指向一個以空字符結束的字符數組,指針的類型是const char*
使用數組初始化vector對象:vector<int> vec(begin(arr), end(arr));
術語表:直接初始化、值初始化、->運算符
第四章 表達式
表達式:最小的計算單元。一個表達式包含一個或多個運算對象,通常還包含一個或多個運算符。表達式求值會產生一個結果。
字面值和變量是最簡單的表達式,其結果就是字面值和變量的值。
表達式本身也可以作為運算對象。
運算符的優先級和結合律
位運算符:檢查和設置二進制位
類型轉換:顯示轉換(static_cast)
術語表:復合表達式、整型提升、短路求值
第五章 語句
表達式語句:在一個表達式的末尾加上分號
switch語句:對括號里的表達式求值,然后和各case標簽的值比較
do while語句:先執行后判斷;條件為假終止循環
goto語句:容易引發錯誤,慎用
try語句塊:throw表達式、catch子句、異常類
術語表:塊、帶標簽語句、異常聲明、terminate
第六章 函數
形參名是可選的:無法使用未命名的形參
局部對象:自動對象、局部靜態對象
引用形參:是對應實參的別名,可避免拷貝
const形參:p190
數組引用形參:形參是數組的引用,有限制(大小固定)
main的形參的使用:處理命令行選項
可變形參:initializer_list類型的形參、省略符形參
返回值:初始化調用點的臨時量
引用返回左值:返回引用的函數
返回花括號包圍的值列表
主函數main的返回值
返回數組指針使用的類型別名:尾置返回類型、decltype
重載、內聯函數、默認實參
constexpr函數:返回常量表達式的函數,被隱式地聲明為內聯函數
調試幫助:assert、NODEBUG
函數指針
術語表:二義性調用、assert、候選函數、可行函數
第七章 類
使用類定義自己的數據類型
this:一個(指向類類型非常量版本的)常量指針,總是指向調用對象
const成員函數:修改this指針的類型(把this設置為指向常量的指針),故該函數不能改變調用它的對象的內容
定義/初始化/拷貝/賦值/銷毀 類的對象
構造函數:類控制其對象的初始化過程的方式
合成的默認構造函數:如果不存在類內的初始值,則默認初始化該成員
構造函數初始值列表:后執行函數體
拷貝對象:初始化、傳值調用、返回一個對象
賦值操作:使用了賦值運算符時
我們不定義上面這些操作(初始化/拷貝/賦值/銷毀),編譯器將替我們合成它們
封裝性:使用訪問說明符,使用戶不可訪問類的部分成員,public成員定義類的接口,private部分封裝了類的實現細節
友元:訪問相關聯的類的私有成員,友元類的成員函數也可訪問
成員函數&內聯:定義在類內部的成員函數是自動inline的,而在類外定義的成員函數必須用inline關鍵字修飾
可變數據成員:mutable關鍵字聲明;即使它是const對象的成員也是可變的
基於const的重載:對某個對象調用重載成員函數時,將根據該對象是否是const決定調用哪個版本
不完全類型:前向聲明的類(僅聲明類),不能定義以不完全類型作為參數或返回類型的函數
委托構造函數
explicit:轉換構造函數、一步類類型轉換
聚合類、字面值常量類
類的靜態成員:不能在類的內部初始化靜態成員,但可以為constexpr的靜態成員提供const整型的類內初始值
術語表:抽象數據類型、顯式構造函數、接口、名字查找、=default
第二部分 C++標准庫
第八章 IO庫
通過一族定義在標准庫中的類型來處理IO
IO類:istream/ostream/iostream、ifstream/ofstream/fstream、istringstream/ostringstream/stringstream
IO類型間的關系:類型ifstream和istringstream都繼承自istream,可將派生類對象當作其基類對象使用
IO對象無拷貝或賦值:不能拷貝或對IO對象賦值,即形參或返回類型必須是引用類型
IO庫條件狀態:可被任何流類使用的一組標志和函數,指出給定流是否可用
輸出緩沖區:保存程序讀寫的數據,可以管理該緩沖區
文件輸入輸出:綁定文件的方式、按指定mode打開文件、關閉關聯文件close
文件模式:類fstream定義的一組標志,在打開文件時指定,用來控制文件如何被使用
術語表:字符串流、stringstream
第九章 順序容器
類型:vector、deque、list、forward_list、array、string
array:一種數組類型,其對象大小是固定的
使用元素類型的默認構造函數:只接受容器大小參數時,類必須要有默認構造函數
容器操作:類型別名,支持<、<=運算符,所有容器都支持相等運算符
emplace操作:構造而非拷貝元素
使迭代器失效的容器操作:p315
容器適配器:為容器操作定義了不同的接口,來與容器類型適配
術語表:適配器、左閉合區間
第十章 泛型算法
標准庫容器定義了很少的操作(添加、刪除元素,訪問首尾元素等),有更多的操作(如查找特定元素、重排元素等)需要通過算法實現。
迭代器令算法不依賴於容器,但算法依賴於元素類型的操作
算法:find、count、accumulate、equal、fill、replace、sort、unique、stable_sort、for_each、transform
插入迭代器:一種向容器中添加元素的迭代器,back_iterator
謂詞作為參數:謂詞是一個可調用的表達式,其返回結果是一個能用作條件的值,如cmp(返回能作為條件的bool值,能調用cmp(a, b))
標准庫算法或使用一元謂詞或使用二元謂詞,一元謂詞意味着該謂詞只能接受一個參數
lambda表達式:當算法要求使用X元謂詞,而實際使用到的謂詞接受的參數個數大於X時,我們需要使用lambda表達式
可調用對象:可對其使用調用運算符的對象,如函數、函數指針、lambda表達式、重載了函數調用運算符的類
bind函數:解決謂詞參數數目問題
插入迭代器:back_inserter、front_inserter、inserter
iostream迭代器:將對應的流當做一個特定類型的元素序列來處理
反向迭代器:需要遞減運算符
_copy版本的算法:將元素寫到一個指定的輸出目的位置
_if版本的算法:接受一個謂詞
鏈表類型list和forward_list優先使用成員函數形式的算法:不使用通用算法,因為它們不支持隨機訪問迭代器
術語表:istream_iterator、ostream_iterator、迭代器類別
第十一章 關聯容器
元素按關鍵字來保存和訪問
類型:map、set、multimap、multiset、及其相應的無需版本(前面加unordered_)
map:關鍵字-值對的集合,關聯數組
set:支持高效的關鍵字查詢操作
pair類型:map中的元素的類型,first成員保存關鍵字,second成員保存對應的值
multi:允許多個元素具有相同的關鍵字
關聯容器不支持順序容器的位置相關的操作(如push_back等),因為其中的元素是根據關鍵字存儲的
關鍵字類型的要求:該類型要求定義了“行為正常”的<運算符
自定義組織一個容器中元素的操作類型:multiset<Sales_data, decltype(compareIsbn)*> bookstore(&compareIsbn);
關聯容器額外的類型別名:key_type、mapped_type、value_type
添加元素:insert、emplace
訪問元素:find(k)、count(k)、low_bound(k)、upper_bound(k)、equal_range(k)
無序容器:組織元素不是通過使用比較運算符,而是使用一個哈希函數和關鍵字類型的==運算符
術語表:hash、哈希函數、嚴格弱序
第十二章 動態內存
標准庫定義了兩個智能指針類型來管理動態分配的對象
每個程序擁有一個內存池,我們稱之為自由空間(或堆),程序用堆來存儲動態分配的對象
動態分配的對象:在程序運行時分配的對象,其生存期由程序來控制
管理動態內存:new在動態內存中為對象分配空間並返回一個指向該對象的指針(我們可以選擇對對象進行初始化);delete接受一個動態對象的指針,銷毀該對象並釋放與之關聯的內存
使用動態內存易出現的問題:內存泄漏、產生引用非法內存的指針
為了更容易地使用動態內存,新的標准庫提供了兩種智能指針類型來管理動態對象
智能指針:負責自動釋放所指向的對象
shared_ptr類:初始化/賦值、支持的操作
make_shared函數:創建一個動態對象並初始化,返回指向該動態對象的shared_ptr
make_shared用其參數來構造給定類型的對象,如調用make_shared<string>時傳遞的參數必須與string的某個構造函數相匹配
shared_ptr的析構函數會遞減它指向的對象的引用計數,如果引用計數變為0,則還會銷毀對象並釋放它占用的內存
即如果有n個shared_ptr指向同一個對象,那該對象的引用計數就是n,於是每銷毀一個shared_ptr時,引用計數就減1
幾種遞增/遞減引用計數的情況:譬如返回一個智能指針將遞增計數,因為在調用點會有一個shared_ptr保存返回來的智能指針
程序使用動態內存的一個原因:程序需要在多個對象間共享數據
Blob類:Blob對象的不同拷貝之間共享相同的元素,實現代碼
直接管理內存:new無法為其動態分配的對象命名,值初始化與默認初始化的區別
new分配的對象都是默認初始化的
通過內置指針管理的動態對象的生存期:直到被顯式釋放之前,局部指針變量離開作用域會被銷毀
delete之后重置指針值:防止空懸指針
shared_ptr與new結合使用:將一個智能指針綁定到一個用new動態分配的內存上,即用new返回的指針來初始化智能指針
用來初始化智能指針的普通指針:默認是指向動態內存的,如果不是,則必須提供自己的操作來替代delete
不要混用智能指針和內置指針:智能指針的特性只在智能指針之間操作才會有效
unique_str類:綁定到一個new返回的指針上,不支持普通的拷貝和賦值操作
不能拷貝unique_str的例外:可以拷貝和賦值一個將要銷毀的unique_ptr
向unique_ptr傳遞刪除器:默認使用delete釋放它指向的對象,可重載一個刪除器;類似於重載關聯容器的比較操作
weak_ptr類:不可控制所指向對象生存期的智能指針,指向由一個shared_ptr管理的對象
StrBlobPtr類:相當於指向StrBlob類的指針,可訪問修改vector<string>的元素,實例代碼
動態數組:一次性為很多元素分配內存
allocator類:允許我們將分配和初始化分離,而new將內存分配和對象構造組合在了一起
allocator支持的操作:分配/釋放內存、構造/銷毀對象
標准庫為allocator類定義了兩個伴隨算法:在分配的原始內存中創建對象
文本查詢程序:標准庫相關內容學習的總結
術語表:釋放器、定位new、引用計數
第三部分 類設計者的工具
第十三章 拷貝控制
類對象的幾個操作:拷貝、移動、賦值、銷毀
五種特殊函數:拷貝構造函數、拷貝賦值運算符、移動構造函數、移動賦值函數、析構函數
通過定義拷貝控制成員:使類的行為看起來像一個值,或像一個指針
行為像值的類:對於類管理的資源,每個對象都擁有一份自己的拷貝
行為像指針的類:多個對象共同管理相同的資源
拷貝並交換:將左側運算對象與右側運算對象的一個副本進行交換,而返回左側對象,常用於定義賦值運算符
拷貝控制示例:練習應用拷貝控制成員
動態內存管理類:該類在運行時分配可變大小的內存空間,自己進行內存分配,如標准庫中的vector類
StrVec類:vector類的簡化版本,練習如何實現動態內存管理類,主要知識點為allocator類的應用
對象移動:移動而非拷貝對象,類似IO類、unique_ptr這樣的類的對象不能拷貝但可以移動
右值引用:必須綁定到右值的引用
標准庫move函數:可顯式地將一個左值轉換為對應的右值引用類型,即可以通過它來獲得綁定到左值上的右值引用
移動構造/賦值函數:直接接管目標對象的資源,而不需要拷貝
挑選移動還是拷貝函數:根據傳遞的實參,如實參是右值,當然選移動
noexcept:聲明函數不會拋出異常
引用限定符:&和&&放在參數列表后面,分別指出this可以指向一個左值(即只能向可修改的左值賦值)或右值
術語表:拷貝初始化、刪除的函數、move、移動迭代器
第十四章 重載運算符與類型轉換
不可重載的運算符::: 、.* 、. 、?:
作為成員還是非成員:非成員的可以是算術、相等性、關系和位運算,成員的有=/[]/()/->/+=/++/解引用
重載輸入運算符>>:需要檢查讀取操作是否成功,即必須處理輸入可能失敗的情況
定義前置/后置版本的遞增/減運算符:為了區別開來,會使后置版本多一個形式上的整型形參
函數調用運算符:可以像使用函數一樣使用該類的對象,與可調用對象的共性,funtion類型
類類型轉換:類型轉換運算符及使用它應避免二義性
術語表:調用形式、類類型轉換、類型轉換運算符、函數表、函數對象
第十五章 面向對象程序設計
面向對象程序設計基於三個基本概念:數據抽象、繼承和動態綁定
OOP概述:數據抽象(將類的接口與實現分離)、繼承(定義相似的類型並對其相似關系建模)、動態綁定(在一定程度上忽略相似類型的區別,而以統一的方式使用它們的對象)
虛函數:某些成員函數,基類希望它的派生類各自定義適合自身的版本
動態綁定(函數調用):使用基類的引用或指針調用一個虛函數時發生動態綁定
派生類可以繼承定義在基類中的成員,但是派生類的成員函數不一定有權訪問從基類繼承而來的成員
派生類對象的組成:一個含有派生類自己定義的非static成員的子對象 + 一個與該派生類繼承的基類對應的子對象(如果由多個基類,此子對象也有多個)
派生類向基類的類型轉換:因為派生類對象中含有與其基類對應的組成部分,所以能把派生類的對象當成基類對象來使用,而我們也能將基類的引用或指針綁定到派生類對象中的基類部分上;編譯器會隱式地執行派生類到基類的轉換!!但該轉換只對指針或引用類型有效
類型轉換帶來的:可以把派生類對象或派生類對象的引用用在需要基類引用的地方,同樣也可以把派生類對象的指針用在需要基類指針的地方
派生類不能直接初始化其對象中的基類部分:和其他創建了基類對象的代碼一樣,必須使用基類的構造函數來初始化它的基類部分
即每個類控制它自己的成員初始化過程
派生類的作用域嵌套在基類的作用域之內:派生類成員可以像使用本類成員一樣使用基類的成員
防止繼承的發生:在類名之后跟一個關鍵字final
抽象基類:含有(或未經覆蓋直接繼承)純虛函數的類,我們不能創建抽象基類的對象
派生類訪問基類的成員:protected成員的特性
三種繼承方式對於訪問控制的影響:派生類對其繼承而來的成員的訪問權限
改變個別成員的可訪問性:使用using聲明來改變派生類繼承的某個名字的訪問級別
繼承中的名字查找:派生類的作用域嵌套在基類中,對象的靜態類型決定了從哪個類開始搜索名字
名字查找先於類型檢查:因為派生類的作用域嵌套在基類中,故其中與基類同名的函數會隱藏基類中的函數,即只要找到此名字的函數就停止向基類搜索
虛析構函數:動態分配繼承體系中的對象,在基類中將析構函數定義成虛函數
繼承與拷貝控制:位於繼承體系中的類進行拷貝控制操作時應注意基類的拷貝控制
繼承的構造函數:派生類可使用using聲明語句繼承基類的構造函數,但不能繼承默認、拷貝和移動構造函數
容器與繼承:使用容器存放繼承體系中的對象
文本查詢程序再探:擴展文本查詢程序,增加更多查詢操作,作為繼承的最后一個例子
術語表:可訪問的、派生類向基類的類型轉換、動態類型、覆蓋、多態性、重構、公有繼承
第十六章 模板與泛型編程
模板是泛型編程的基礎
模板的編寫格式:函數/類模板、類模板的友元、成員模板
模板實參的深入:類型轉換、顯式實參
重載與模板:特例化版本優先、非函數模板優先
引用折疊和右值引用參數:函數參數是右值引用
可變參數模板:sizeof...運算符、參數包、包擴展
模板特例化:模板的一個特例化版本,並非重載模板
術語表:模板參數、模板參數列表、類型參數、實例化、成員模板、參數包、函數參數包、類型轉換
第四部分 高級主題
第十七章 標准庫特殊設施
介紹四個具有特殊目的的標准庫設施,以及IO庫中某些不常用的部分
tuple類型:類似pair,但包含的類型更多
biset類型:相對位運算來說,處理二進制數更容易
正則表達式:很好的描述字符序列的方法
隨機數:隨機數引擎+分布類型,我們說的隨機數發生器就是指分布對象和引擎對象的組合
IO庫再探:一系列操縱符控制輸入輸出格式、未格式化的輸入/輸出操作允許將一個流當做一個無解釋的字節序列來處理、定位流中位置並隨機訪問
術語表:tupe、biset、regex、cmatch、smatch、未格式化IO、隨機數引擎、隨機數分布、操縱符、種子
第十八章 用於大型程序的工具
介紹在設計大型程序時最有用的三個特效,包含異常處理、命名空間和多重繼承
noexcept異常說明:指定某個函數不會拋出異常
noexcept運算符:可與noexcept說明符混合使用
異常說明與指針、虛函數和拷貝控制:函數的異常說明對於使用函數的影響
異常類層次:標准庫異常類構成了一套繼承體系
命名空間:作用域 + using聲明 + using指示
命名空間中的名字&多個文件:using聲明的作用域+using指示的弊端
重載與命名空間:命名空間對函數的匹配過程的影響
多重繼承:從多個直接基類產生派生類
多重繼承的初始化過程及其拷貝控制
虛繼承:每個派生類最多一次繼承同一個類
先初始化虛基類部分,再構造其他非虛基類
術語表:構造函數順序、文件中的靜態聲明、全局命名空間、命名空間污染、重新拋出
第十九章 特殊工具與技術
介紹幾種用於特定類別問題的特殊工具和技術
重載new和delete:自定義內存分配的細節
使用定位new形式構造對象:傳遞一個地址,在一個特定的、預先分配的內存地址上構造對象,而不分配內存
運行時類型識別:typeid運算符 + dynamic_cast運算符
枚舉類型:定義新的類型
類成員指針:數據成員指針 + 成員函數指針
嵌套類:作用域 + 名字查找 + 與外層類的關系
union類型:任意時刻只有一個數據成員有值
局部類:類定義在某個函數內部 + 名字查找
固有的不可移植的特性:為了支持低層編程而定義的,不可移植的特性是指因機器而異的特性,包括位域、volatile限定符和鏈接指示
術語表:匿名union、判別式、RTTI、定位new表達式、枚舉類型、dynamic_cast、鏈接指示
附錄
靜態成員 p268
析構函數:銷毀元素,釋放內存
類型別名:typedef int arrT[10]; arrT是一個由10個整型元素組成的數組的別名
與類的對象交互必須使用該類的接口
通過作用域運算符來使用被隱藏的名字
Sales_data類:p240
Screen類:p243
StrBlob類:p405
StrBlobPtr類:p421
文本查詢程序:p430 T13.42
Message類:p461
StrVec類:p465 T13.44