C++基礎學習(C++ Primer——未看完版本)
2020-08-09 22:55:24
C++基礎學習
C++基礎
變數和基本型別
-
變數
- 無符號和有符號加減會把有符號轉化爲無符號
- 無符號只是解釋方式不同,運演算法則遵循二補數法則
-
字面值常數
-
0開頭-8進位制
-
0x | 0X開頭-16進位制
-
字面值型別
- 是:算術型別,參照和指針
- 否:自定義類,IO庫,string
-
宣告和定義
-
參照和指針
-
參照
- 參照並非物件,定義參照就無法系結到另外的物件,使用就是存取最初系結的物件
-
指針
-
const
-
處理型別
-
decltype
-
int i=42,&r=i,*p=&i;
decltype®=int&
decltype(r+0)=int
decltype(*p)=int&----解除參照指針可以得到指針所指的物件的參照
decltype((i))=int&
-
與auto的區別
- 如果使用參照型別,auto會識別爲其所指物件的型別,decltype則會識別爲參照的型別。
-
當我們使用decltype作用於某個函數時,它返回函數型別而非指針型別,因此我們需要顯示的加上*已表明我們需要返回指針
-
前處理器
字串,向量和陣列
string
-
getline
-
size_type與帶符號數混用會造成歧義
-
+兩側運算物件至少一個爲string
vector
迭代器
陣列與指針
- int *a[10]; //a陣列含有10個指針整形
int &a[10]; //錯誤,不存在參照的陣列
int (*a)[10]; //a是一個指針,指向一個含有10個整數的陣列
int (&a)[10]; //a是一個參照,參照一個含有10個整數的陣列
int *(&a)[10]; // a是陣列的參照,陣列含有十個指針
- 原則:從內到外,從右到左
- 內建下標運算子所用的索引值是有符號型別
多維陣列
- 使用auto
- 使用型別別名
- 要使用範圍for語句處理多維陣列,除了最內層的回圈外,其他所有回圈的控制變量都應該是參照型別
表達式
基礎
逗號運算子
語句
迭代語句
-
範圍for
- 預存了end()的值,所以不能通過範圍for增加容器物件的元素
-
回圈的區別
-
do while
- 塊中定義的變數,while不可用
- do塊先執行,後執行while
-
while和for
函數
函數基礎
-
區域性靜態變數
- 程式終止才被銷燬,在此期間即使物件所在函數結束執行也不會對他有影響
返回型別和return語句
函數過載
constexpr函數
- 函數的返回型別及所有形參型別都是字面值型別,而且函數體中必須有且僅有一條return語句
類
認識類
-
定義在類內部的函數是隱式的inline函數
-
參數列表後的const
封裝
- 封裝實現了類的介面和實現的分離,隱藏了類的實現細節,使用者只能接觸到類的介面
友元
-
特點
- 只能出現在類定義內部,但類內出現的具體位置不限
- 友元不是類的成員,不受區域存取控制級別的約束
- 在友元之外再專門對函數進行一次宣告
特性
-
可變數據成員
- mutable型別的數據可在const函數內部修改它的值
-
名字查詢
- 名字查詢的順序:由內而外、自上而下
- 在類中,型別名要特殊處理,最好是定義在類的一開始,並且不能與外層作用域中同名
-
類定義處理
型別轉化
-
抑制建構函式定義的隱式轉化
- explicit,初始化時該關鍵詞無影響
- explicit只對一個實參的建構函式有效,需要多個實參的建構函式不能用於執行隱式轉化
- explicit只允許出現在類內的建構函式宣告處
- 用於顯示宣告建構函式,同時也抑制拷貝建構函式
類的靜態成員
-
宣告靜態成員
- 不與任何物件系結,不包含this指針,所以不能在static函數體內使用this指針
- 靜態成員函數不能宣告成const
IO庫
IO類
-
IO物件無拷貝或賦值,甚至不能顯式構造初始化
-
輸出快取
順序容器
迭代器
- 公共介面
- forward_list迭代器不支援遞減運算子(–)
新增元素
-
特例
- forward_list有自己的insert和emplace
- forward_list不支援push_back和emplace_back
- vector和string不支援push_front和emplace_front
-
insert
emplace
- 會在容器管理的記憶體空間直接建立物件,而呼叫push_back則會建立一個區域性臨時變數,並將其壓入容器中
容器操作可能使迭代器失效
容器適配器
-
預設
- stack和queue基於deque實現;
priority_queue基於vector實現
-
例子
- stack<string,vector>str_stack
在vector上實現的空棧
-
擴充套件
- array,forward_list不能用來構造適配器
因爲所有適配器具有新增,刪除以及存取尾元素
- stack
push_back,pop_back,back
除了上面兩個(下面 下麪不再闡述)
- queue
back,push_back,front,push_front
list和deque都可以,但vector不行
- priority_queue
front,push_back,pop_back,隨機存取能力
vector,deque,不能基於list
泛式演算法
標準庫演算法
- 對迭代器而不是容器操作,因此演算法不能直接新增或刪除元素,例如unique不能刪除重複元素,而是將重複元素移到後面
只讀演算法
-
accumulate
- 接受3個參數,前兩個是需要求和的元素範圍,第三個參數是和的初值,同時第三個參數型別決定了函數使用哪個加法運算子和返回值的型別
寫演算法
- 向目的位置迭代器寫入數據的演算法假定目的位置足夠大,能容納要寫入的元素(位置足夠大代表序列大小,並非可用記憶體大小,即reserve無效,resize纔可以)
lambda
-
格式:[capture list](parameter list)->return type {function body}
尾置返回,可以忽略參數列表和返回型別,但永遠保留捕獲列表和函數體
如果lambda函數體包含任何單一return語句之外的內容,且未指定返回型別,則返回void
-
捕獲列表
- 捕獲列表只用於區域性非static變數,lambda可以直接使用區域性static變數和它所在函數之外宣告的名字
-
可變lambda
-
值捕獲
- lambda不會改變捕獲的拷貝變數,加上mutable即可
-
參照捕獲
- 取決於此參照指向的是一個const型別還是非const型別
參數系結
標頭檔案functional
- bind,待定參數:placeholders::_1
- 謂詞
(一元-find_if;
二元-sort)
- 系結的參數爲參照:ref()函數
迭代器
-
插入迭代器
- inserter接受兩個參數,第一個參數是容器,第二個是指向給定容器的迭代器
- 理解例子:
*it=val;
||
V
it=c.insert(it,val);
++it;
list特定容器演算法
- 其他容器演算法不會改變容器大小,但list和forward_list會改變容器大小,例如list的unique就會直接刪除重複的
關聯容器
map
set
型別別名
-
key_type
-
mapped_type
-
value_type
- 對於set,與key_value相同
- 對於map,爲pair<const key_type,mapped_type>
動態記憶體
原因
- 程式不知道自己需要使用多少物件(容器)
- 程式不知道所需物件的準確型別(模板)
- 程式需要在多個物件間共用數據
shared_ptr
-
建構函式
- 接受指針參數,需要直接初始化
- explicit,抑制隱式
- 正確例子:shared_ptrp(new int(1024));
錯誤例子:shared_ptrp=new int(1024);
-
陷阱
- 不使用相同的內建指針值初始化多個智慧指針
- 不delete get()返回的指針
- 不使用get()初始化或reset另一個智慧指針
- 當你使用的智慧指針管理的資源布氏new分配的記憶體,記住傳遞一個刪除器
unique_ptr
weak_ptr
-
特性
- 不控制所指向物件生存期的智慧指針,指向由一個shared_ptr管理的物件
- 系結到shared_ptr不會改變shared_ptr的參照計數
- 參照計數爲0,即使有weak_ptr指向物件,物件也還是會被釋放
動態陣列
-
初始化
- new可以分配大小爲0的陣列,返回一個合法非空指針
此指針不能解除參照,因爲它不指向任何元素
-
釋放
-
關於unique_ptr
- 不能使用點和箭頭成員運算子,因爲指向的是一個數組
- 當一個unique_ptr指向一個數組時,可以使用下標運算子來存取陣列中的元素
-
關於shared_ptr
allocator類
-
與new的不同
- new將記憶體分配和物件構造組合在一起
allocator將記憶體分配和物件構造分離
-
分配的記憶體是原始的,未構造的
拷貝控制
拷貝建構函式
-
定義
- 一個建構函式的第一個參數是自身類型別的參照,且任何額外參數都有預設值,此建構函式是拷貝建構函式
- 合成拷貝建構函式是預設的拷貝建構函式(自己未定義,編譯器自動生成的)
可以逐元素地拷貝一個數組型別的成員
-
觸發條件
- 物件作爲實參傳遞給非參照型別的形參
- 從返回型別爲非參照型別的函數返回一個物件
- {}初始化列表——陣列,聚合類
- 容器呼叫insert和push,進行拷貝初始化
-
注意
- 編譯器爲了優化,也會繞過拷貝建構函式,但拷貝構造必須存在且可存取
解構函式
-
特點
- 沒有返回值,不接受參數,因此不能被過載,只有唯一一個解構函式
- 成員按初始化順序的逆序銷燬
- 內建型別沒有解構函式
-
觸發條件
- 變數離開作用域
- 物件被銷燬,成員被銷燬
- 容器被銷燬,其元素也被銷燬
- delete銷燬
- 對於臨時變數,當建立它的完整表達式結束時被銷燬
-
注意
- 解構函式自身並不直接銷燬成員,成員是在解構函式體之後隱含的解構階段中被銷燬的
三/五法則
- 需要解構函式的類也需要拷貝和賦值操作
- 需要拷貝操作的類也需要賦值操作,反之亦然
阻止拷貝
物件移動
運算子過載
基本概念
::
.*
.
?:
不能被過載
遞增和遞減運算子
-
區分前置後置運算子
- 後置版本接受一個額外的int型別形參(後來者排隊)
-
規則
- 後置運算子應該返回物件原值返回的形式是一個值而非參照,與內建版本保持一致
函數呼叫運算子
-
lambda是函數物件
- 編譯器將lambda表達式翻譯成一個未命名類的未命名物件,在lambda表達式產生的類中含有一個過載的函數呼叫運算子(),lambda產生的類當中的函數呼叫運算子是一個const成員函數
-
可呼叫物件與function
-
不同類型可能具有相同的呼叫形式
-
定義函數表,使用function儲存
-
過載函數與function
型別轉換運算子
模板與泛式程式設計
定義模板
-
函數模板
-
非型別模板參數
-
函數模板和類別範本成員函數的定義通常在標頭檔案中
-
類別範本
- 顯示模板實參
- 一個類別範本的每個範例都形成一個獨立的類
沒有特殊存取許可權
- 在一個類別範本的作用域內,我們可以直接使用模板名而不必指定模板實參
標準庫特殊設施
tuple
-
型別
- 任意數量成員,每個成員型別可以不同
- tuple<T1,T2,T3,…,Tn> t (v1,v2,…,vn)