時間:2014.06.25
地點:基地
-----------------------------------------------------------------------------
一、在編譯時捕捉缺陷
捕捉缺陷可在編譯時發生也可在運行時發生,只要有可能,我們應該盡力在編譯時捕捉缺陷。
原因:
1.在編譯期檢測到的缺陷,給出的是一條文本信息,正確描述了所發生的錯誤是什麼,發生在哪以及發生的位置。
2..完整的編譯完整地覆蓋了程序中的所有代碼,即若編譯器沒有返回錯誤或警告,即可相信程序中百分之百的不存在編譯時可檢測到的錯誤。(這點對於運行時測試 就無法保證了,當代碼龐大時,很難保證所有分支都被測試到,也無法保證程序每行代碼都會至少執行一次,即無法保證代碼測試100%的覆蓋,且即便同一段代碼,對於不同的輸入,測試結果也可能不一樣)
3.編譯時捕捉到的錯誤可以節省程序維護時間,早發現早超生(運行時錯誤難以複製和跟蹤)
基於這樣一些等等的原因,我們應該儘量在編譯器捕捉到程序缺陷,於是我們在編寫代碼時,應該能使程序具有自我診斷功能,方便在編譯器尋找缺陷。
-----------------------------------------------------------------------------
二、正確處理類型
問題描述
有時,我們編寫一個函數處理一些自定義數據類型,比如我們已經定義好兩個類型:類Apple和類Orange,現有函數聲明如下:
void DoSomeWithOrange(const Orange& orange);
如果我們在調用DoSomeWithOrange時,不小心傳入了Apple對象,如下:
Apple an_apple(some_inputs);
DoSomeWithOrange(an_apple);
很多場合下,這樣的誤傳類型的代碼是可以編譯通過的,因爲編譯器總是試圖儘可能地幫你進行類型轉換,使之滿足要求,即Apple可能在這偷偷地轉換爲Orangte類型,我們並不期待這種轉換,於是有必要在編譯器就檢測到這樣的失誤。
發生這麼偷偷的類型轉換有兩種情況:
a.Orange類具有一個只接受Apple類型參數的構造函數。如下:
class Orange
{
public:
Orange(const Apple& apple);
};
或
class Orange
{
publick:
Orange(const Apple& apple,const Banana* p_banana=0);
};
像上面這樣的類,在調用需要Orange類的地方,如果誤傳實參Apple類型,Apple類型就會發生這種偷偷的類型轉換。
class Orange
{
public:
explicit Orange(const Apple& apple);
};
或
class Orange
{
publick:
explicit Orange(const Apple& apple,const Banana* p_banana=0);
};
這樣,可以防止編譯器執行隱式自動類型轉換,使得在需要期望接受Orange的地方就必須使用Orange了。
b.當然,當提供一個轉換操作符將Apple類型對象顯式轉換爲Orange類型,也會發生這種偷偷的隱式類型轉換
class Apple
{
public:
//......
operator Orange() const;
};
解決辦法是,我們爲Apple類提供了轉換爲Orange的顯式轉換操作符
class Apple
{
public:
//......
Orange AsOrange() const;
};
於是,這樣,我們調用函數時可如下調用:
Apple apple(some_inputs);
DoSomethingWithOrange(apple.AsOrange()); //顯式轉換
-----------------------------------------------------------------------------
三、使用枚舉類型
先定義如下兩個枚舉,分別表一週中的星期和一年的月份
enum{SUM,MON,TUE,WED,THU,FRI,SAT};
enum{JAN=1,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC};
我們知道,這些實際上都是整數,當我們有一個期望接受一週中的星期作爲參數的函數時:
void FuncExpectingDayOfWeek(int day_of_week);
現在,假如我們誤傳了一年中的某個月編譯也將順利通過:
FuncExpectionDayOfWeek(JAN);
在這裏因爲星期和月份的表示所以編譯順利通過,爲了避免在編譯時就捕捉在這種誤傳,我們應該使用創建新類型的枚舉
typedef enum{SUM,MON,TUE,WED,THU,FRI,SAT}DayOfWeek;
enum{JAN=1,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC}Month;
void FuncExpetingDayOfWeek(DayOfWeek day_of_week);
現在,當傳 JAN時將會發生編譯錯誤。
總的一點說來,大多數情況我們應該儘量避免隱式類型轉換,這就允許我們充分利用編譯器檢查不同變量類型的功能,在早期編譯時捕捉到潛在的錯誤。但也總有一些錯誤只能在運行時被檢測得到,那也是不可避免的,所以只是儘量在編譯器檢測到錯誤。
-----------------------------------------------------------------------------
四、總結
禁止隱式類型轉換:用關鍵字explicit聲明接受1個參數的構造函數,儘量不要使用轉換操作符,而是在類中提供更好的類型轉換方法成員。
不要使用枚舉創建整型常量,而是使用它們創建新類型。