在現實世界中,還有這樣一類特殊的條件選擇:
如果明天是晴天,我就穿T恤;
如果明天是陰天,我就穿襯衣;
如果明天是雨天,我就穿外套。
之所以說這是條件選擇,是因為它根據不同的情況執行了不同的動作;而之所以說它特殊,是因為這些不同情況(晴天、陰天、雨天)屬於同一條件(天氣情況)。只要是條件判斷,我們就可以用if語句將其表達出來,利用前面介紹過的if…else if…並列條件選擇語句,我們可以將這個看天穿衣的場景表達如下:
// 用並列條件選擇實現的看天穿衣 #include <iostream> using namespace std; // 枚舉可能的天氣情況 enum Weather { SUNNY = 1, // 晴天,指定其值為1 CLOUDY, // 陰天,其值遞增為2 RAINY, // 雨天,其值遞增為3 }; int main() { cout<<"請輸入明天的天氣(1-晴天;2-陰天;3-雨天):"; int nW = 0; // 獲取用戶輸入天氣情況 cin>>nW; // 對天氣情況進行判斷 if(SUNNY == nW) // 如果是晴天 { // 輸出晴天該穿的衣服 cout<<"晴天穿T恤"<<endl; } else if(CLOUDY == nW) // 如果是陰天 { cout<<"陰天穿襯衣"<<endl; } else if(RAINY == nW) // 如果是雨天 { cout<<"雨天穿外套"<<endl; } else { cout<<"不知道明天是什麼天氣,你愛穿什麼穿什麼吧"<<endl; } return 0; }
使用並列條件選擇語句,雖然能夠把這種並列選擇場景表達出來,可是我們不得不書寫多個if…else if…分支,要書寫多個相似的條件表達式,顯得有些繁瑣。為了簡化代碼,同時為了使這種並列條件選擇表達得更加清晰,C++提供了專門的switch語句以代替復雜的並列條件選擇語句,其語法格式如下:
switch( 條件量 ) { case 常量值1: { 語句1; } break; case 常量值2: { 語句2; } break; //… case 常量值n: { 語句n; } break; default: { 默認語句; } }
其中,條件量就是要進行判斷的條件,它可以是某個變量,比如,我們這裡表示天氣狀況的nW變量,也可以是某個更加復雜的表達式。而多個常量值就是這個條件量可能的取值,比如,我們這裡的條件量nW的可能取值就是SUNNY(晴天)、CLOUDLY(陰天)或者RAINY(雨天)。在執行的時候,switch語句會首先計算條件量的值,然後將這個值按照從上到下的順序依次與各個case分支的常量值進行比較。如果兩者相等,則進入相應case分支執行,直到遇到分支中的break關鍵字,結束整個switch語句的執行;如果兩者不相等,則繼續向下判斷後面的case分支。如果直到最後都沒有遇到與條件量相等的常量值,則進入表示默認情況的default分支開始執行最終完成整個switch語句。default分支表示對所有不符合case分支條件的例外情況的默認處理,它是可選的,如果我不需要處理例外情況,就可以省略掉default分支。如果沒有default分支,而同時又找不到匹配的case分支時,程序則不執行任何語句而直接結束switch語句,如圖4-2所示。
圖4-2 switch語句的執行流程
有了switch語句,我們就可以用它替換if…else if…並列條件選擇語句,將“看天穿衣”的並列條件選擇簡化為:
// 用switch語句實現的並列條件選擇 // 以表示天氣狀況的nW作為條件量,根據不同的天氣穿不同的衣服 switch(nW) { case SUNNY: // 以表示晴天的SUNNY作為常量值,進行對晴天狀況的處理 cout<<"晴天穿T恤"<<endl; break;// 完成對晴天狀況的處理,用break結束整個switch語句 case CLOUDY: // 處理陰天 cout<<"陰天穿襯衣"<<endl; break; case RAINY: // 處理雨天 cout<<"雨天穿外套"<<endl; break; default:// 對例外情況進行默認的處理 cout<<"不知道這是什麼天氣,你愛穿什麼穿什麼吧"<<endl; }
在這裡,我們用表示天氣狀況的變量nW作為條件量,而用標識各種天氣狀況的枚舉值作為各個case分支的常量值。在執行的時候,switch語句會將保存了天氣狀況的條件量nW從上往下地與各個case分支的常量值進行相等比較,也就相當於並列條件選擇語句中的“if(SUNNY == nW)”這樣的條件判斷。這種相等比較從上到下依次進行,直到遇到兩者相等的分支,則進入執行,隨後遇到break關鍵字而結束整個switch語句的執行。這樣,switch語句實現的邏輯判斷跟之前用if…else if…並列條件選擇語句實現的完全一致,而代碼卻更加簡潔,而且各種情況用case分支單獨列出,邏輯也更加清晰。所以,在表達這種針對同一條件不同情況的條件選擇時,我們應該優先選擇使用switch語句。
在使用switch語句時需要特別注意的是每個case分支末尾的break關鍵字。它的作用是跳(break)出當前的case分支,結束整個switch語句的執行。在上面的例子中,如果用戶輸入的nW是1,表示明天是晴天。因為SUNNY分支的值跟nW相等,那麼switch語句會進入“case SUNNY”分支執行,輸出:
晴天穿T恤
接著遇到break關鍵字,就會忽略掉後面的其他case分支而直接結束整個switch語句的執行。而如果這裡沒有break關鍵字,它就會繼續向下執行後繼的case分支,直到遇到break關鍵字或者是其後的所有分支執行完畢。所以,如果這個switch語句中缺少了break關鍵字, 那麼用戶輸入1,輸出就成了:
晴天穿T恤
陰天穿襯衣
雨天穿外套
不知道這是什麼天氣,你愛穿什麼穿什麼吧
看看,整個都亂套了!所以,在使用switch語句時,一定要注意在每個case分支末尾加上break關鍵字,表示這個分支處理完畢,結束整個switch語句的執行。
當然,事無絕對。大多數時候,我們需要在每個case分支後加上break關鍵字,而在某些特殊情況下,也就是多個case分支有共同的功能需要完成時,一個case分支功能是另外一個case分支功能的一部分,兩個case分支有包含與被包含的關系,這時也可以有意地去掉包含分支中的break關鍵字,並將其放在靠上的位置,從而達到共用被包含分支中實現公共功能的代碼。例如,我們在KFC點餐時,有漢堡套餐和雞翅套餐可供選擇。漢堡套餐就是一個漢堡而已,而雞翅套餐是在漢堡套餐的基礎上再加一對雞翅而成。在這個場景下,兩個case分支(漢堡套餐和雞翅套餐)就有了公共功能(一個漢堡),而且兩者形成了包含與被包含的關系(雞翅套餐包含漢堡套餐,而漢堡套餐被雞翅套餐包含),在這種情況下,就可以省略掉包含case分支(雞翅套餐)的break關鍵字,並將其放在相對靠上的位置,以實現共用公共功能:
cout<<"請選擇您需要的套餐(1-漢堡套餐;2-雞翅套餐)"<<endl; int nOrder = 0; cin>>nOrder; // 獲取用戶選擇 switch(nOrder) { case 2: // 將包含case分支放在靠上的位置 cout<<"一對雞翅"<<endl; // 完成獨有的功能 // 注意,這裡省略掉了case分支末尾的break關鍵字 case 1: // 將被包含case分支置於靠下的位置 cout<<"一個漢堡"<<endl; // 完成公共功能 break; // 保留break關鍵字,結束switch語句 default: cout<<"無法識別的選項,請重新選擇"<<endl; }
在這個例子中,我們就有意地省略掉了第一個case分支的break關鍵字,當我們輸入1表示選擇漢堡套餐時,switch語句會進入“case 1”分支執行,輸出“一個漢堡”後,遇到末尾的break關鍵字,從而結束整個switch語句的執行。最終,我們得到的漢堡套餐的內容是:
一個漢堡
而當我們輸入2表示選擇雞翅套餐時 ,switch語句會首先進入“case 2”分支執行,輸出“一對雞翅”後,因為這裡沒有break關鍵字,所以它會繼續向下進入“case 1”分支執行,輸出“一個漢堡”,這時它才遇到break關鍵字,結束整個switch語句的執行。最終,我們得到的雞翅套餐的內容是:
一對雞翅
一個漢堡
這裡雖然我們省略了某些case分支末尾的break關鍵字,但不僅沒有造成邏輯上的錯誤,反而達到了共用公共功能代碼的效果。
在使用switch語句時,還需要注意以下幾個問題:
(1) switch關鍵字後括號中的條件量必須是整型的數值變量或表達式,或者是能夠被轉換為整型的其他類型,比如字符類型或者枚舉類型等。
(2) 因為switch之後的條件量是整型,為了與之比較,所以case之後的常量值也必須是整型。它通常是一些表示各種情況的枚舉值,比如上面例子中的SUNNY、CLOUDLY等,也可以直接是常量數字,如上面例子中表示選項的常量數字1和2,甚至可以是只有常量參與運算的常量表達式。
(3) 各個case分支的常量值不能相等,即不能出現兩個相同條件的case分支。