Assertion 的使用目的,就是要防止客戶對程式庫的誤用。以 Design by Contract 的原則再加上 OOP 的術語,簡單說來:就是要確保物件在執行操作或行為後還要維持其內部狀態的正確。
假設描述物件這個行為的程式本身正確無誤,而作業系統也沒來找碴,那使物件狀態脫軌的必定來自物件使用者傳入錯誤的引數。
就如同程式行為發生“例外”一樣,程式庫的使用者知道如何偵測錯誤的物件狀態,但卻不知如何處理...
傳統 C 語言的 assert 做法,就是一偵測到要確認的條件不成立了,就立刻終止整個程式的執行,並列印一些偵錯訊息出來。
但是,在這個愈來愈趨向動態的程式世界。有時連客戶都無法確保傳入的引數是正確的,原因可能不是客戶不夠小心,而是在動態的世界裡,這是無法避免的。
這時,在 C++ 中可行的個解法,就是丟出“例外”。被丟出的例外可以被客戶捕捉,並作一些處理措施。萬一客戶不處理,才將程式終結掉。
我這裡使用的,就是裹著 Assertion 的例外,並利用 template 來讓客戶決定要丟出的例外種類:
From: "Jiang Yu-Kwan" Sent: Monday, June 18, 2001 4:40 PM Subject: Re: Fw: JavaOne特別報導
我再看了一下,它支援的是 generic programming,而 template 只是在C++下的實作方式。
以 JAVA 設計的哲學,它可能把GP搞得跟 C++ 的 template 語法很像,但骨子裡卻不必preprocessor處理,而是直接在 run time support。
而 assertion 的支援,只是為了支援 Design by Contract ,其支援的完整性,可能更勝 C。
因為 C++ 對 assertion 沒有更進一步的支援(直接沿用C的做法)。所以, JAVA 在這點有很大的改進空間。
以下我就舉例說明一下,如何製造一個 C++ 版本的 assertion 功能:
1: // assertion.h 2: //... 3: 4: template <class Exception> void Assert( bool assertion ) 5: { 6: if (! assertion) throw Exception(); 7: } 8: //... 9:
經修改後,我現在實際使用的 assertion 版本如下:
1: // Assertion for C++ version. 2: template <class Exception> inline void Assert( bool assertion ) 3: { 4: #ifndef NO_CPP_ASSERTION 5: if (! assertion) throw Exception(); 6: #endif 7: }
1: // user.c 2: #include "assertion.h" 3: //... 4: class Date { 5: public: 6: class Bad_arg{}; 7: setMonth( int mon ); 8: //... 9: private: 10: //... 11: }; 12: 13: void Date::setMonth( int mon ) 14: { 15: // 確保設定的月數在正確的範圍,否則, 16: // 就丟出Bad_arg的例外。 17: Assert<Bad_arg>(1<=mon && mon<=12); 18: //... 19: } 20: //... 21:
更進一步的探討可以參考 C++ 之父, Bjarne Stroustrup 所著的 《The C++ Programming Language 3rd Edition》。