C++異常處理模型除了支持面向過程的C風(fēng)格程序中的異常處理外(就是沒有面向?qū)ο蟮母拍?,完全是C程序,整個程序?qū)嶋H就是函數(shù)的集合,但卻用C++ 編譯器來編譯這樣的C程序,所以這樣的程序中是可以a使用C++的異常處理機制的,要不怎么說C++是兼容C語言的呢?但是需要注意的是,單純的C語言程序中是不能使用C++異常處理模型進(jìn)行編程的。是不是有點說拗口了?有點糊涂了呢?其實很簡單,那就是如果程序中使用了C++異常處理機制,也即代碼中有 try、catch和throw關(guān)鍵字,那么就必須使用C++編譯器來編譯這個程序。許多程序員朋友們在這里有一個理解上的誤區(qū),認(rèn)為只有程序中使用了面向?qū)ο蟮母拍?,即使用class關(guān)鍵字來定義一個類結(jié)構(gòu)才算得上C++程序,其實這種理解是片面的,如果程序中采用了C++異常處理機制,那么也有理由認(rèn)為這是一個C++程序,哪怕程序的代碼完全是C語言風(fēng)格的,并且這樣的程序用C編譯器來編譯肯定將會報錯,提示未定義的try標(biāo)示符等等錯誤信息),還支持面向?qū)ο蟪绦蛑袑ο髵伋龅漠惓L幚怼?BR> C++異常處理模型的確和面向?qū)ο笫蔷o密結(jié)合的,除了在相遇篇中介紹到的用對象來描述程序中出現(xiàn)的異常之外,C++異常處理模型也對在面向?qū)ο蟪绦蛑械膶ο髮嵗鶔伋龅漠惓W髁俗钔晟频闹С趾吞幚?。也許大家會覺得這很容易,沒什么了不起的地方。但恰恰相反,實際上這才是C++異常處理模型最成功、最不可思議和最閃光的地方。而且由于C++異常處理模型對面向?qū)ο笥辛撕芎玫闹С趾图嫒荩攀沟肅++異常處理模型本身的實現(xiàn)變得特別復(fù)雜,因為它需要跟蹤每一個對象的運行情況和狀態(tài)(關(guān)于C++異常處理模型的實現(xiàn),會在愛的秘密篇中有詳細(xì)剖析)。本文和接下來的幾篇文章將講述當(dāng)對象實例拋出異常時將如何處理。
對象的生命周期一般有三種狀態(tài):構(gòu)造、運行和析構(gòu)銷毀。因此對象拋出的異常也有這三種區(qū)別。是在對象構(gòu)造時拋出的呢?還是對象運行時拋出的呢?或是析構(gòu)對象時拋出的?這三種不同時候拋出的異常會將會產(chǎn)生不同的結(jié)果。本文首先討論最常見的一種情況,在對象運行時拋出的異常,也即執(zhí)行對象的成員函數(shù)時出現(xiàn)的異常。
對象的成員函數(shù)拋出的異常
1、老方法,看例子先,如下:
class MyTest_Base
{
public:
MyTest_Base (string name = “”) : m_name(name)
{
cout << “構(gòu)造一個MyTest_Base類型的對象,對象名為:”< }
virtual ~ MyTest_Base ()
{
cout << “銷毀一個MyTest_Base類型的對象,對象名為:”< }
void Func() throw()
{
throw std::exception(“故意拋出一個異常,測試!”);
}
void Other() {}
protected:
string m_name;
};
void main()
{
try
{
MyTest_Base obj1(“obj1”);
// 調(diào)用這個成員函數(shù)將拋出一個異常,注意obj1的析構(gòu)函數(shù)會被執(zhí)行嗎?如果
// 會,又是在什么時候被執(zhí)行呢?
obj1.Func();
obj1.Other();
}
catch(std::exception e)
{
cout << e.what() << endl;
}
catch(...)
{
cout << “unknow exception”<< endl;
}
}
C++程序員不難看出上面的程序的運行結(jié)果,如下:
構(gòu)造一個MyTest_Base類型的對象,對象名為:obj1
銷毀一個MyTest_Base類型的對象,對象名為:obj1
故意拋出一個異常,測試!
從運行結(jié)果可以得出如下結(jié)論:
(1) 對象的成員函數(shù)出現(xiàn)異常時,catch block能捕獲到異常,這一點就像C語言中的普通函數(shù)一樣,沒什么特別的地方;
(2)對象的成員函數(shù)出現(xiàn)異常時,對象的析構(gòu)函數(shù)將會得到執(zhí)行(這一點很神奇吧!當(dāng)然在這里不會做過多研究,在剖析C++異常處理模型的實現(xiàn)時再做詳細(xì)的闡述),這里與C++標(biāo)準(zhǔn)中規(guī)定的面向?qū)ο蟮奶匦允窍嘁恢碌?,?gòu)造了的對象就必須保證在適當(dāng)?shù)牡胤揭鰳?gòu)它,以釋放可能的資源。因此前面說的“C++異常處理模型對面向?qū)ο筇峁┝酥С趾图嫒荨笔怯懈鶕?jù)的。而且注意它的析構(gòu)函數(shù)是在異常處理模塊之前執(zhí)行的,這一點更與C++標(biāo)準(zhǔn)中規(guī)定的面向?qū)ο蟮奶匦允且恢碌模?dāng)對象出了作用域時,它就必須要被析構(gòu)。
2、把上面的程序小改一下,運行再看結(jié)果,如下:
void main()
{
// obj1對象不在trycatch域中,注意它的析構(gòu)函數(shù)在什么時候被執(zhí)行?
MyTest_Base obj1(“obj1”);
try
{
// obj2和obj3對象都在trycatch域中,其中obj3.Func()函數(shù)被調(diào)用,因此
// obj3會拋出異常,特別需要注意的是,obj2的析構(gòu)函數(shù)會被執(zhí)行嗎?如果
// 會,又是在什么時候被執(zhí)行呢?
MyTest_Base obj2(“obj2”), obj3(“obj3”);
obj3.Other();
// 調(diào)用這個成員函數(shù)將拋出一個異常
obj3.Func();
// 注意:obj4對象在構(gòu)造之前,函數(shù)中就有異常拋出。所以obj4對象將不會
// 被構(gòu)造,當(dāng)然也不會被析構(gòu)
MyTest_Base obj4(“obj4”);
obj3.Other();
}
catch(std::exception e)
{
cout << e.what() << endl;
}
catch(...)
{
cout << “unknow exception”<< endl;
}
}
上面的程序也難看出其運行結(jié)果,如下:
構(gòu)造一個MyTest_Base類型的對象,對象名為:obj1
對象的生命周期一般有三種狀態(tài):構(gòu)造、運行和析構(gòu)銷毀。因此對象拋出的異常也有這三種區(qū)別。是在對象構(gòu)造時拋出的呢?還是對象運行時拋出的呢?或是析構(gòu)對象時拋出的?這三種不同時候拋出的異常會將會產(chǎn)生不同的結(jié)果。本文首先討論最常見的一種情況,在對象運行時拋出的異常,也即執(zhí)行對象的成員函數(shù)時出現(xiàn)的異常。
對象的成員函數(shù)拋出的異常
1、老方法,看例子先,如下:
class MyTest_Base
{
public:
MyTest_Base (string name = “”) : m_name(name)
{
cout << “構(gòu)造一個MyTest_Base類型的對象,對象名為:”<
virtual ~ MyTest_Base ()
{
cout << “銷毀一個MyTest_Base類型的對象,對象名為:”<
void Func() throw()
{
throw std::exception(“故意拋出一個異常,測試!”);
}
void Other() {}
protected:
string m_name;
};
void main()
{
try
{
MyTest_Base obj1(“obj1”);
// 調(diào)用這個成員函數(shù)將拋出一個異常,注意obj1的析構(gòu)函數(shù)會被執(zhí)行嗎?如果
// 會,又是在什么時候被執(zhí)行呢?
obj1.Func();
obj1.Other();
}
catch(std::exception e)
{
cout << e.what() << endl;
}
catch(...)
{
cout << “unknow exception”<< endl;
}
}
C++程序員不難看出上面的程序的運行結(jié)果,如下:
構(gòu)造一個MyTest_Base類型的對象,對象名為:obj1
銷毀一個MyTest_Base類型的對象,對象名為:obj1
故意拋出一個異常,測試!
從運行結(jié)果可以得出如下結(jié)論:
(1) 對象的成員函數(shù)出現(xiàn)異常時,catch block能捕獲到異常,這一點就像C語言中的普通函數(shù)一樣,沒什么特別的地方;
(2)對象的成員函數(shù)出現(xiàn)異常時,對象的析構(gòu)函數(shù)將會得到執(zhí)行(這一點很神奇吧!當(dāng)然在這里不會做過多研究,在剖析C++異常處理模型的實現(xiàn)時再做詳細(xì)的闡述),這里與C++標(biāo)準(zhǔn)中規(guī)定的面向?qū)ο蟮奶匦允窍嘁恢碌?,?gòu)造了的對象就必須保證在適當(dāng)?shù)牡胤揭鰳?gòu)它,以釋放可能的資源。因此前面說的“C++異常處理模型對面向?qū)ο筇峁┝酥С趾图嫒荨笔怯懈鶕?jù)的。而且注意它的析構(gòu)函數(shù)是在異常處理模塊之前執(zhí)行的,這一點更與C++標(biāo)準(zhǔn)中規(guī)定的面向?qū)ο蟮奶匦允且恢碌模?dāng)對象出了作用域時,它就必須要被析構(gòu)。
2、把上面的程序小改一下,運行再看結(jié)果,如下:
void main()
{
// obj1對象不在trycatch域中,注意它的析構(gòu)函數(shù)在什么時候被執(zhí)行?
MyTest_Base obj1(“obj1”);
try
{
// obj2和obj3對象都在trycatch域中,其中obj3.Func()函數(shù)被調(diào)用,因此
// obj3會拋出異常,特別需要注意的是,obj2的析構(gòu)函數(shù)會被執(zhí)行嗎?如果
// 會,又是在什么時候被執(zhí)行呢?
MyTest_Base obj2(“obj2”), obj3(“obj3”);
obj3.Other();
// 調(diào)用這個成員函數(shù)將拋出一個異常
obj3.Func();
// 注意:obj4對象在構(gòu)造之前,函數(shù)中就有異常拋出。所以obj4對象將不會
// 被構(gòu)造,當(dāng)然也不會被析構(gòu)
MyTest_Base obj4(“obj4”);
obj3.Other();
}
catch(std::exception e)
{
cout << e.what() << endl;
}
catch(...)
{
cout << “unknow exception”<< endl;
}
}
上面的程序也難看出其運行結(jié)果,如下:
構(gòu)造一個MyTest_Base類型的對象,對象名為:obj1