4.1 基礎
- 函數調用也是一種特殊的運算符,它對運算對象的數量沒有限制。
- C++ 的表達式要么是左值,要么是右值。左值可以位于賦值語句的左邊,右值則不可以。
- 當一個對象被用作右值的時候,用的是對象的值;當對象被用作左值的時候,用的是對象的身份。
【mark】 - 優先級規定了運算對象的組合方式,但是沒有說明運算對象的求值順序,一般不會明確指定求值順序。
- 對于沒有指定執行順序的運算符,如果表達式指向并修改了同一個對象,將會引發錯誤并產生未定義的行為。
cout << i << ++i << endl; // 未定義的
4.2 算術運算符
- 算術運算符的運算對象和求值結果都是右值。
- 在表達式求值之前,小整數類型的運算對象被提升成較大的整數類型,所有運算對象最終會轉換成同一類型。
- 一元正(負)號運算符作用于一個指針或者算數值時,返回運算對象(取負)的提升后的副本。
bool b = true;
bool b2 = -b; // b2 is true
m = (m / n) * n + m % n
,則 m % n
符號與 m
相同。
4.3 邏輯和關系運算符
- 邏輯和關系運算符的運算對象以及求值結果都是右值。
- 相等性測試與布爾字面值
if (val) {} // 如果 val 是任意的非 0 值
if (!val) {} // 如果 val 是 0
if (val == true) // 如果 val 等于 1
4.4 賦值運算符
int i = 0, j = 0, k = 0; // 初始化而非賦值
const int ci = i; // 初始化而非賦值
1024 = k; // 錯誤 字面值是右值
i + j = k; // 錯誤 算術表達式是右值
ci = k; // 錯誤 ci 是常量左值
- 賦值運算的結果是它的左側對象,并且是一個左值,結果的類型是左側運算對象的類型。
- 賦值運算符滿足右結合律。
4.5 遞增和遞減運算符
- 遞增和遞減運算符有兩種形式:前置版本
++i
和后置版本 i++
。這兩種運算符必須作用于左值運算對象,前置版本將對象本身作為左值返回,后置版本將對象原始值的副本作為右值返回。 - 除非必須,否則不用遞增和遞減運算符的后置版本。
4.6 成員訪問運算符
4.7 條件運算符
4.8 位運算符
- 位運算符的運算對象如果是“小整型”,則會被自動提升為整數類型。
- 位運算符如何處理帶符號數的符號位是未定義的,因此建議僅將位運算符用于處理無符號數。
- 移位運算符(IO運算符)滿足左結合律。
sizeof 運算符
sizeof
運算符返回一條表達式或者一個類型名字所占的字節數,返回 size_t
類型的常量表達式。
sizeof (type)
sizeof expr
sizeof
運算符滿足右結合律。- 在
sizeof
的運算對象中解引用一個無效指針是安全的,因為指針沒有被真正使用。 - 對數組執行
sizeof
運算得到整個數組的大小,對 sting 或 vector 執行 sizeof
運算只返回該類型固定部分的大小。
4.10 逗號運算符
- 逗號運算符先對左側的表達式求值,然后將結果丟棄掉,再對右側的表達式求值,返回右側的結果。
4.11 類型轉換
- 算術轉換:運算符的運算對象將轉換成最寬的類型。
- 整型提升:轉換后的類型要容納原類型所有可能的值。
- 如果一個運算對象是無符號類型,另一個是帶符號類型:
無符號類型不小于帶符號類型:帶符號類型轉成無符號類型;
帶符號類型大于無符號類型:轉換結果依賴于機器; - 指針的轉換
常量整數值 0 或者字面值 nullptr 能轉換成任意指針類型;
指向任意非常量的指針能轉成 void;
指向任意對象的指針能轉成 const void; - 轉換成布爾類型:指針或算術值為 0,結果為 false,否則為 true。
- 轉換成常量:允許將指向非常量的指針(引用)轉換成相應的常量指針(引用)。
- 類類型能定義由編譯器自動執行的轉換,不過編譯器每次只能執行一次類類型的轉換。
- 強制轉換
cast-name <type> (expression)
// 把一個較大的算術類型賦值給較小的類型。
double slope = static_cast<double>(j) / i;
// 找回存在于 void* 指針的值
double *p = static_cast<double*>(p);
// 改變運算對象的底層 const
const char *pc;
char *p = const_cast<char*>(pc);
// todo