-
短路求值
邏輯與運算符(&&)和邏輯或運算符(||)都是先求左側運算對象的值再求右側運算對象的值,當且僅當左側運算對象無法確定表達式的結果時纔會計算右側運算對象的值。這種策略稱爲短路求值。
- 對於邏輯與運算符(&&)來說,當且僅當左側運算對象爲真時纔對右側運算對象求值。
- 對於邏輯或運算符(||)來說,當且僅當左側運算對象爲假時纔對右側運算對象求值。
-
關係運算符與賦值運算符
- C++中bool值可以轉化成爲其他算數類型:false轉化成0,true轉化成1;
- C++中允許用賦值運算作爲條件。
int a = 10, b = 5, c = 2;
if (a > b > c)//a>b爲true,1與c進行比較
{
cout << "enheng" << endl;
}
if (a = b)//將b的值賦給a,如果b的值不是0,則爲真
{
cout << a << endl;//5
}
-
遞增遞減運算符
推薦使用前置版本的遞增運算符:前置版本的遞增運算符(++i)避免了不必要的工作 , 它把值加 1 後直接返回改變了的運算對象。與之相比 , 後置版本(i++)需要將原始值存儲下來以便於返回這個未修改的內容。如果我們不需要修改前的值 , 那麼後置版本的操作就是一種浪費。
-
解引用與遞增運算符
*p++:後置遞增運算符的優先級高於解引用運算符,因此 *p++ 等價於 *( p++)。p++ 把p的值加 1,然後返回p的初始值的副本作爲其求值結果,此時解引用運算符的運算對象是p未增加之前的值。最終,這條語句輸出p開始時指向的那個元素,並將指針向前移動一個位置。
-
解引用與點運算符
(*p).empty():因爲解引用運算符的優先級低於點運算符,所以執行解引用運算的子表達式兩端必須加上括號。
-
位運算符
- 位運算符有左移<<、右移>>、位求反~、位與&、位或|、位異或^。
- 位運算符作用於整數類型的運算對象,並把運算對象看成是二進制位的集合。
- 移位運算符(<<、>>,又叫IO運算符)的優先級不高不低,介於中間:比算術運算符的優先級低,但比關係運算
符、賦值運算符和條件運算符的優先級高。
cout << 5 + 10 << endl;//15
cout << (5 < 10) << endl;//1,需要加括號,否則報錯
-
sizeof運算符
- sizeof運算符返回一條表達式或一個類型名字所佔的字節數。sizeof 運算符滿足右結合律 , 其所得的值是一個 size_t 類型的常量表達式。運算符的運算對象有兩種形式:
sizeof ( type )
sizeof expr - sizeof並不實際計算其運算對象的值。
- 在sizeof的運算對象中解引用一個無效指針仍然是一種安全的行爲 , 因爲指針實際上並沒有被真正使用。sizeof不需要真的解引用指針也能知道它所指對象的類型。
- C ++11新標準允許我們使用作用域運算符來獲取類成員的大小。通常情況下只有通過類的對象才能訪問到類的成員 , 但是 sizeof 運算符無須我們提供一個具體的對象 , 因爲要想知道類成員的大小無須真的獲取該成員。
- 對數組執行 sizeof 運算得到整個數組所佔空間的大小,等價於對數組中所有的元素各執行一次 sizeof 運算並將所得結果求和。注意,sizeof運算不會把數組轉換成指針來處理。
- 因爲執行 sizeof 運算能得到整個數組的大小,所以可以用數組的大小除以單個元素的大小得到數組中元素的個數。
char chars[] = "hello";
auto byteSize1 = sizeof(char);
auto byteSize2 = sizeof chars;
cout << byteSize1 << " " << byteSize2 << endl;//1 6
int num[] = { 1,2,3 };
auto byteSize3 = sizeof(num);
auto length = byteSize3 / sizeof(num[0]);
cout << byteSize3 << " " << length << endl;//12 3
-
強制類型轉換(命名的強制類型轉換):
- 一個命名的強制類型轉換具有如下形式 : cast-name < type > ( expression ) ; 其中 , type 是轉換的目標類型,expression 是要轉換的值。cast-name是 static_cast 、dynamic_cast、const_cast 和 reinterpret_cast中的一種 。
- static_cast:任何具有明確定義的類型轉換,只要不包含底層 const ,都可以使用 static _ cast ;當需要把一個較大的算術類型賦值給較小的類型時, static _ cast 非常有用。
- dynamic_cast:dynamic_cast 支持運行時類型識別。
- const_cast :只能改變運算對象的底層const。對於將常量對象轉換成非常量對象的行爲,我們一般稱其爲“去掉 const 性質
- ”。const_cast參數只能是指針,不能用const_cast改變表達式的類型。
- reinterpret_cast:通常爲運算對象的位模式提供較低層次上的重新解釋。
int a = 10, b = 3;
double slope1 = a / b;//3
double slope2 = static_cast<double>(a) / b;//3.333
const int* num;
int* _num = const_cast<int*>(num);
-
空語句
- 如果在程序的某個地方,語法上需要一條語句但是邏輯上不需要,此時應該使用空語句。
- 一種常見的情況是,當循環的全部工作在條件部分就可以完成時,我們通常會用到空語句。例如,我們想讀取輸入流的內容直到遇到一個特定的值爲止,除此之外什麼事情也不做。
- 多餘的空語句並非總是無害的,如在一個while判斷中,條件部分只有判斷,則會造成死循環。
string s;
while (cin >> s && s != "not")
{
;//空語句
}
-
Switch內部的變量定義
switch 的執行流程有可能會跨過某些 case 標籤。如果程序跳轉到了某個特定的 case ,則 switch 結構中該 case 標籤之前的部分會被忽略掉。這種忽略掉一部分代碼的行爲引出了一個有趣的問題:如果被略過的代碼中含有變量的定義該怎麼辦?
答案是:如果在某處一個帶有初值的變量位於作用域之外,在另一處該變量位於作用域之內,則從前一處跳轉到後一處的行爲是非法行爲。
int num = 10;
switch (num)
{
case 5:
//int a = 0;//錯誤,會提示:a的初始化操作由"case"標籤跳過
int a;//正確
break;
case 10:
a = 0;
a++;
cout << a << endl;
break;
default:
break;
}