C++的那些事:表達式與語句

表達式

1,應該把函數調用當作是一種運算符,這種運算符對參與運算的對象沒有數量限制。

2,關於“左值(lvalue)”和“右值(rvalue)”可以做一個簡單的歸納:當一個對象被用作右值的時候,用的是對象的值(內容);當對象被用作左值的時候,用的是對象的身份(在內存中的位置)。

更具體的左值與右值的舉例:C++ priemr 5ed P121

3,運算符的優先級規定了運算對象的組合方式,但是沒有說明運算對象按照什麼順序求值,在大多數的情況下,不會明確求值的順序,比如對於下面的表達式:

int i= f1() + f2();

先調用f1還是先調用f2是未知的。因此,對於這種運算符來說避免多個運算對象共同修改同一個變量,如下面的代碼中,最終輸出是未能確定的:

int i=0;
cout<< i << "" << ++i << endl; // 未定義

但C++中有4種運算符是明確規定了運算對象的求值順序的:邏輯與“&&”、邏輯或"||"、條件(?:)運算符、逗號運算符","。這也是爲什麼在我們自己定義的類類型中,一般不會去重載這幾種操作符。

4,短路求值:邏輯與運算符和邏輯或運算符都是先求左側運算對象的值再求右側運算對象的值,當且僅當左側運算對象無法確定表達式的結果時纔會計算右側運算對象的值。

5,區別i++與++i

後置操作符需要先保存原來的值,再將i+1,然後返回原來的值的副本;而前置操作符,只需要在原來值上加1,然後返回。所以++i比i++效率更高,當然如果i爲int類型或指針時,編譯器會對i++進行優化,但如果是其他類類型或複雜類的迭代器時就不會了。

6,注意解除引用操作符與++操作符的優先級,在實際代碼中爲了簡潔經常將*(i++)寫爲*i++。因爲++的優先級高於解除引用操作符。

7,在使用條件操作符時,儘量避免寫出深度嵌套的條件操作符。另外條件操作符的優先級非常低,在表示式中使用時要注意加括號,比如:cout<<(i<j?i:j);

8,關於sizeof運算符。sizeof的運算結果是編譯時的常量,注意下面的代碼的值:

int a[10];
int* p = a;
int n1 = sizeof(a) / sizeof(*a); // n1=10
int n2 = sizeof(p) / sizeof(*p); // n2=1

sizeof運算符小貼士:

對char或者類型爲char的表達式執行sizeof運算,結果爲1。
對引用類型執行sizeof運算得到被引用對象年佔空間的大小。
對指針執行sizeof運算得到指針本身所佔空間的大小。
對解引用指針執行sizeof運算得到的指針指向的對象所佔空間的大小,指針不需要有效。
對數組執行sizeof運算得到的整個數組所佔空間的大小,等價於對數組中所有的元素各執行一次sizeof運算並將所得結果求和。注意sizeof運算不會把數組轉換成指針來處理。
對sting對象或vector對象執行sizeof運算只返回該類型固定部分的大小,不會計算對象中的元素佔用了多少空間。

9,在複合表達式求值時,要特別注意運算符的優先級與結合性。特別地,!=與==的優先級小於<=,>=等關係運算符。

10,類型轉換

1)隱式轉換

下面情況下,編譯器會自動地轉換運算對象的類型:

在大多數表達式中,比int類型小的整數值首先提升爲較大的整數類型。
在條件中,非布爾值轉換成布爾類型。
初始化過程中,初始值轉換成變量的類型;在賦值語句中,右側運算對象轉換成左側運算對象的類型。
如果算術運算或關係運算的運算對象有多種類型,需要轉換成同一種類型。
函數調用時,實參與形參之間的類型轉換。
類類型可以定義一些轉換函數。

2)顯式轉換

static_cast<Type>:任何具有明確定義的類型轉換,只要不包含底層const
const_cast<Type>:只能改變運算對象底層const
reinterpret_cast<Type>:通常爲運算對象的位模式提供較底層次上的重新解釋。
dynamic_cast<Type>:運行時類型識別。

語句

1,和大多數語言一樣,C++提供了條件執行語句、重複執行相同代碼的循環語句和用於中斷前前控制流的跳轉語句。

2,在使用塊狀語句時注意,在塊狀語句內定義的變量作用域只在塊狀區域內。特別地,在控制語句,比如if或for語句中,初始化或定義的變量,都只有塊區域的作用域。

3,switch語句的使用。case標號必須是整形常量表達式,不允許在switch語句內定義變量如果在它下面還有case或default語句,因爲這樣會在某些情況下,在沒有執行變量定義的case分支的情況下,執行變量定義下面case分支。除非把變量定義在代碼塊內。

4,在for循環中,如果有continue語句,會跳下continue後面的語句,但是不會跳變for語句中的計數器變化語句。

5,範圍for語句

範圍for語句是C++11新引入的內容,這種語句可以遍歷容器或其他序列的所有元素。它的語法形式爲:

for(declaration:expression)
  statement;

其中expression表示的必須是一個序列,比如用花括號括起來的初始值列表或者vector或string等類型對象。這些類型的共同特點是擁有能返回迭代器的begin和end成員。

declaration定義一個變量,序列中的每個元素都得能轉換成該變量的類型。確保類型相容最簡單的辦法是使用auto類型說明符,這個關鍵字可以令編譯器幫助我們指定合適的類型。如果需要對序列中的元素執行寫操作,循環變量必須聲明成引用類型。

下面是用範圍for語句來遍歷一個vector的例子。

vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (auto &r : v)
{
   r *= 2;
}

在使用範圍for時語句時,不能通過範圍for語句增加vector對象的元素。因爲在範圍for語句中,預存了end()的值。一旦在序列中添加(刪除)元素,end函數的值就可能變得無效了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章