昨天寫博客時用的是博客園自帶的 MarkDown編輯器,一點兒都很差用,插入代碼塊和段落縮進很難搞,傳統的 MarkDown語法說四個空格或者一個 Tab就能夠縮進,結果博客園自帶的編輯器裏這樣作竟然不行。再搜了不少個 MarkDown編輯器後,決定仍是使用小書匠,由於這個好像能夠直接把文章發佈到博客園上。這就很方便了。話很少說,進入正題。
1.運算符的三個關鍵點:優先級、結合律、求值順序。
2.在重載運算符時,運算對象的類型和返回值的類型能夠改變,但運算對象的個數、運算符的優先級和結合律都是沒法改變的。
3.decltype做用於表達式時,當表達式的求值結果是左值時,獲得的是引用類型;當求值結果是右值時,獲得的是值類型。html
int a = 5;
int *p = &a;
decltype(*p) p1; // p1是 int &
decltype(&p) p2; // p2是 int **
4.C++語言對於大多數的運算符並無規定求值順序,對於這些運算符,若是表達式指向並修改了同一個對象,將會引起錯誤併產生未定義的行爲。數組
int i = 0;
cout << i << " " << ++i << endl; // 未定義
編譯器可能先求 ++i的值再求 i的值,也可能先求 i的值再求 i的值。此表達式的行爲不可預知。有 4種運算符規定了它們的求值順序,分別是 &&、||、條件(?:)和逗號(,)。
5.對於整數的除法和取餘運算中,C11新標準中規定商一概向 0整除(即直接切除小數部分)。安全
21 % -5; /* 結果是 1 */ 21 / -5; /* 結果是 -4 */
-21 % -5; /* 結果是 -1 */ -21 / -5; /* 結果是 4 */
6.對於二元運算符,算術>關係>邏輯>賦值。因此在條件語句中,賦值部分一般加上括號。
if ((i = get_value()) != 42)
7.對於遞增/遞減運算符,優先使用前置版本,由於後置版本須要在修改前將原始值存儲下來,效率更低。
8.條件運算符的優先級很是低,在輸出表達式中使用條件運算符時要在兩端加上括號。編輯器
cout << ((grade < 60) ? "fail" : "pass"); // 輸出 pass或 fail
cout << (grade < 60) ? "fail" : "pass"; // 輸出 1或者 0後根據 cout的值輸出 pass或 false
9.若是運算對象是帶符號的且它的值爲負,那麼位運算符如何處理運算對象的「符號位」依賴於機器。並且,此時的左移操做可能會改變符號位的值,是一種未定義行爲。所以建議僅將位運算符用於處理無符號類型。
10.位異或運算符(^),兩個運算對象相同,結果爲 0,反之爲 1。真值表以下ide
0 | 1 | |
---|---|---|
0 | 0 | 1 |
1 | 1 | 0 |
11.sizeof,並不實際計算其運算對象的值。所以,在做用於解引用的指針時,即便該指針是一個未初始化的指針也不會有影響,它返回的是所值類型的空間大小。
對 char或者類型爲 char的表達式執行 sizeof運算,結果得 1。
對引用類型執行 sizeof運算,獲得被引用對象所佔空間的大小。
對指針執行 sizeof運算,獲得指針自己所佔空間的大小。
對解引用指針執行 sizeof運算,獲得指針所指的對象所佔空間的大小,指針不需有效。
對數組執行 sizeof運算獲得整個數組所佔空間的大小,並不會將數組轉換爲指針。
對 string或 vector對象執行 sizeof運算,只返回該類型固定部分的大小,和裏面存放了多少數據無關。
12.對無符號類型和帶符號類型進行運算,其結果比較複雜,也依賴於具體機器,因此應該儘可能避免無符號類型和帶符號類型的運算!
13.類型轉換函數
double d = 3.14;
int i = static_cast<int>(d);
void *p = &d;
double *pd = static_cast<double*>(p); // 將 void*轉換回初始的指針類型