C++ primer 5th : 第四章筆記
第四章: 表示式
基本概念:
運算子: 一元 , 二元 , 三元
組合運算子 和 運算物件 :
優先順序: 使用 () 避免優先順序的混淆的問題
結合律:
求值順序: 二元運算子兩邊的表示式計算順序可能存在差異 , 應該避免
對優先順序 , 結合率 , 求值順序的解釋:
//如下表達式: //我們假設 g() 的操作是將全域性變數 i = 10 的值 乘以 2 返回 //我們假設 h() 的操作是將全劇變數 i 的值 + 2 返回f() + g() * h() + j() // 優先順序 : 存在於組合運算當中 , 也就是多個運算子參與 , 優先順序是運算子 與 運算子之間的關係 // 結合率 : 我們針對 上述表示式 可以 使用 結合率 的方式改變運算子的優先順序 // ( f() + g() ) * h() + j() // 求值順序 : 對於 單個二元運算子來說 , 先算右邊 還是 先算左邊 好像只有在 邏輯運算子 : || && 上才有體現 , 但是在 * 上可能存在差異 , 如上 , // 如果我們先算左邊 , 在算右邊 ; 那 g() * h() 的結果就是 20 * 22 = 440 // 如果我們先算右邊 , 在算左邊 ; 那 g() * h() 的結果就是 24 *12 = 288// 所以我覺得 能不在一個運算子兩邊修改 共有的部分 是最好的。
運算物件轉換 :
表示式中勻允許不同型別之間的轉換 , 編譯器會自動的轉換
int 還會有型別提升
在算術型別之間的運算 需要保證 運算結果不溢位 , 且精度損失降低到最小 , 才有運算結果的型別一定是其中的最高型別。
過載運算子:
將運算子 賦予 在某一個非基本型別上面新的含義
左值 與 右值 :
將一個物件當作左值來使用 : 代表的是當前物件本身
將一個物件當作右值來使用 : 代表的是當前物件的拷貝
需要右值的地方可以使用 左值代替 , 但是反過來通常不行
decltype 與 左值 右值:
如果 decltype 的是一個左值型別 , 那麼得到一定是一個引用型別 , 如果decltype 的是一個右值型別 , 那麼得到的一定是一個 普通型別
#include <iostream> using namespace std; int main() { int a = 10; //普通的類新 int int & b = a; //引用型別 int & decltype(b) c = a; //c 的型別為 int & c = 20; //修改C 就是 修改a cout << a << endl; //結果為20 return 0; } ~decltype 的是的左值型別
算數運算子:
略
邏輯運算子:
注意 : && || 有運算子求值順序的規定 , 先算左邊在算右邊 , 左邊滿足的順序右邊不再計算 , 這就是短路
賦值運算子:
-
- = 左邊必須是一個可以修改的左值
- C++11 允許使用 {} 擴起來的初始值列表做右值
- 連續賦值運算 滿足 右邊結合率 : a = b = 10
- 賦值運算子優先順序低 : if ( 1 != (i = get_value())
遞增運算子 和 遞減運算子:
- ++ , -- 運算子 需要左值物件 : (i++)++ 錯誤 , i++返回的是右值
成員運算子:
. 與 ->
條件運算子:
> , < , >= ......
位運算:
& , | , ~ , ^
sizeof 運算子:
sizeof(型別) 可以獲得該型別佔用的記憶體大小 , C++ 可以讓sizeof 直接訪問 類的成員的 , 以此的其成員型別佔用的記憶體的大小. sizeof (class::number)
- sizeof(陣列) : 陣列不會退化成指標)
- sizeof(類型別) : 固有成員的記憶體和 : 不包括成員指向的 堆空間的記憶體
- sizeof 返回的型別是一個 constexpr
逗號運算子:
結合律從左邊向右邊 , 最後的結果為最右邊的表示式子 , 且如果最右邊的表示式是左值 , 整個表示式結果為左值 , 否則為右值
型別轉換:
如果兩個型別之間可以相互轉換 , 那麼他們就是有關聯的.
無須程式設計師的介入的型別轉換稱為隱式型別轉換.
顯式型別轉換:
static_cast<>():
不能擦除引用 , 指標 的 底層 const 屬性。
大範圍型別 向 小範圍型別 , 高精度 向 低精度 : 告訴編譯器我是故意轉換的 , 而且我能確保這樣作的後果沒有問題 , 你把警告給我關了吧
const_cast<>():
只能改變物件的頂層const屬性 , 不能值型別轉換:
只有當底層const指向的物件不是 const , 才能進行擦除const :
#include <iostream> using namespace std; int main() { int a = 10; //a 為非const const int & b = a; //底層const , 但是 a 為非const int & c = const_cast<int &>(b); //我們可以擦除掉const 屬性 c = 30; cout << a << endl; //30 : 成功修改 const int aa = 10; //aa為const const int & bb = aa; //指出底層const ,底層確實也是const int & cc = const_cast<int &>(bb); //擦除掉底層的const , 但是為cc重新開闢了空間,也就是 cc 和 aa 指向不是同一個記憶體區域了 cout << aa << endl; //10 cout << cc << endl; return 0; }
dynamic_cast<>()
用於具有繼承體系之間的轉換 指標和引用 , 類必須具有虛擬函式 , 父類指標指向的 子類物件向 向子類指標轉換 , 或者父類引用指向子類的向子類引用轉換使用:
父類指標 指向父型別物件 向 子型別指標轉換 | 一個父類的兩個子類之間轉換 最後為 NULL
父類引用 指向父型別物件 向 子型別引用轉換 丟擲 std::bad_cast 異常
#include <iostream> class A{ public: virtual ~A(){} } class B :public A{ }; class C :public A{ }; int main() { C * c = new C(); B * b = new B(); A * a = new A(); B *bc = dynamic_cast<B*>(c); //2個子類之間不能 dynamic_cast if(NULL == bc) { cout <<"2 個子類指標之間不能發生轉換!" << endl; } B *ba = dynamic_cast<B*>(a); //父類轉換成子類 , 不安全 if(NULL == ba) { cout <<"父類指標 指向 父類物件 不能向子類指標轉換!"<<endl; } A ra; A & aa = ra; try{ B & b = dynamic_cast<B &>(aa); }catch(std::bad_cast){ cout <<"父類引用 指向 父類物件 不能向子類引用轉換!" <<endl; } return 0; } 輸出結果 : 2 個子類指標之間不能發生轉換! 父類指標 指向 父類物件 不能向子類指標轉換! 父類引用 指向 父類物件 不能向子類引用轉換!
reinterpret_cast<>():
不建議使用