這是進階主題。
在 MFC 3.0 版和更新版本中,例外狀況處理巨集已變更為使用C++例外狀況。 本文說明這些變更如何影響使用巨集的現有程式代碼行為。
本文涵蓋下列主題:
例外類型和 CATCH 宏
在舊版 MFC 中,CATCH 巨集使用 MFC 的運行時類型資訊來判斷例外狀況的類型;換句話說,例外狀況的類型是在捕獲點決定的。 不過,使用C++異常時,異常的類型總是在擲出點由擲出異常物件的類型決定。 在罕見情況下,若擲出的物件的指標類型與物件類型不同,這會導致不相容。
下列範例說明 MFC 3.0 版與舊版之間這項差異的結果:
TRY
{
THROW((CException*) new CCustomException());
}
CATCH(CCustomException, e)
{
TRACE("MFC 2.x will land here\n");
}
AND_CATCH(CException, e)
{
TRACE("MFC 3.0 will land here\n");
}
END_CATCH
此程式代碼在 3.0 版中的行為不同,因為控件一律會傳遞至具有相符例外狀況宣告的第一個 catch 區塊。 throw 表達式的結果
THROW((CException*) new CCustomException());
即使它被建構為 CException*,仍會作為 CCustomException 拋出。 MFC 2.5 版和更早版本中的 CATCH 巨集會使用 CObject::IsKindOf 在運行時間測試類型。 因為表達式
e->IsKindOf(RUNTIME_CLASS(CException));
若為真,第一個 catch 區塊會捕捉例外。 在 3.0 版中,使用 C++ 異常來實作許多異常處理巨集,第二個 catch 區塊與拋出的 CException 相匹配。
這類程序代碼並不常見。 當例外狀況對象傳遞至另一個接受泛型 CException*的函式時,它通常會顯示,它會執行「預先擲回」處理,最後擲回例外狀況。
若要解決此問題,請將 throw 運算式從函式移至呼叫端程式碼,並在產生例外狀況時擲回編譯器當時所知的實際類型的例外狀況。
Re-Throwing 例外狀況
catch 區塊無法擲回它所攔截的相同例外狀況指標。
例如,此程式代碼在舊版中有效,但 3.0 版會有非預期的結果:
TRY
{
// Do something to throw an exception.
AfxThrowUserException();
}
CATCH(CException, e)
{
THROW(e); // Wrong. Use THROW_LAST() instead
}
END_CATCH
}
在 catch 區塊中使用 THROW 會導致刪除指標 e ,讓外部 catch 網站會收到無效的指標。 使用 THROW_LAST 重新擲回 e。
如需詳細資訊,請參閱 例外狀況:攔截和刪除例外狀況。