異常類之基類


1.C++中的異常

C++異常處理語法元素try-catch語句
  • try語句處理正常代碼邏輯  (但有可能產生異常,產生異常時拋出異常並轉到catch語句塊里面的代碼)
  • catch語句處理異常情況
  • try語句中的異常由對應的catch語句處理
  • C++通過throw語句拋出異常信息(一般在try語句中)

 

throw和return區別
throw異常的返回一個值,這個值就代表了異常,    拋到catch語句塊 
return正常的返回一個值
 
C++ 異常處理分析
(1)throw拋出的異常必須catch處理
  • 當前函數能夠處理異常(含有catch語句塊,程序繼續往下執行
  • 當前函數無法處理異常,則函數停止執行並返回,由上層函數進行處理了
(2)未被處理的異常會順着函數調用棧向上傳播,直到被處理為止,否則程序將停止執行。如果一直未處理則會到main函數,該函數中若果仍沒有try..catch語句直接退出
 

(3)同一個try語句可以跟上多個catch語句

  ①catch語句可以定義具體處理的異常類型

  ②不同類型的異常由不同的catch語句負責處理

  ③try語句中可以拋出任何類型的異常

  ④catch(…)用於處理所有類型的異常

  ⑤任何異常都只能被捕獲(catch)一次

(4)異常處理的匹配規則

 

 

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 double divide(double a, double b)
 6 {
 7     const double delta = 0.000000000000001;
 8     double ret = 0;
 9 
10     if( !((-delta < b) && ( b < delta))){
11         ret = a / b;
12     }else{
13         throw 0; //產生除0異常
14     }
15 
16     return ret;
17 }
18 
19 //匹配規則(自上而下,嚴格匹配、不進行類型轉換)
20 void Demo1()
21 {
22     try{
23         throw 'c';  //拋出字符型的異常
24     }catch(int i){
25         cout << "catch(int i)" << endl;
26     }catch(double d){
27         cout << "catch(double d)" << endl;
28     }catch(char c){ //只能被這里的catch捕獲
29         cout << "catch(char c)" << endl;
30     }
31 }
32 
33 void Demo2()
34 {
35     throw "Demo2";   //const char*
36 }
37 int main()
38 {
39     cout << "main() begin" << endl;
40 
41     try{
42         double c = divide(1, 0);//產生異常
43         cout <<"c = " << c << endl; //無法被執行到!
44     }catch(...){
45         cout << "Divide by zero..." << endl;
46     }
47 
48     Demo1();
49 
50     try{
51         Demo2();
52 53       catch(char* c)
54      {
55         cout << "catch(char* c)" << endl;
56     }
57     catch(const char* c)
58         {
59         cout << "catch(const char* c)" << endl;
60     }catch(...)
61      {
62        //寫位置最后
63         cout << "catch(...)" << endl;
64     }
65 
66     cout << "main() end" << endl;
67     return 0;
68 }
View Code

 

2.異常類的構建

  • 異常的類型可以是定義類型
  • 對於類類型異常的匹配依舊是至上而下嚴格匹配(不能強制類型的轉換)
  • 賦值兼容性原則(子類的對象可以直接復制給父類的對象,父類的指針可以直接指向子類的對象在異常匹配中依然使用 (出現父類對象是可以用一個子類對象代替)
  • 一般而言:
    ------匹配子類異常的catch放在上部
    ------匹配父類異常的catch放在下部

3、異常類族

現代C++庫必然包含充要的異常類族 
異常類族是數據結構類所以來的“基礎設施
 
  頂層父類Exception是一個抽象類,不能定義對象,用於被繼承的。
這一節就是實現這個抽象基類的。
目的:當程序拋出異常時(有可能會是一個字符串、文件名、行號),能夠捕捉到這個異常,並打印處異常的信息等。
要實現的幾個函數:
構造函數:對收到的異常進行初始化工作
1     Exception(const char* message); 
2     Exception(const char* file,int line);
3     Exception(const char* message,const char* file,int line);

由於初始化工作差不多,為了代碼整潔我們將相同的操作封裝成了一個函數即:

void  init(const char*,const char*,int);//由於三個構造函數中的邏輯很相似,所以可以將相似的部分統一放到一個函數init()

此外還需要保存一些初始化變量的成員變量

1 char* m_message;//m_message指向一個字符串,用於說明當前的異常信息
2 char* m_location;//m_location指向一個字符串,用於說明當前的異常位置

由於涉及到堆空間即需進行深拷貝,就不能使用默認的拷貝構造函數和賦值操作符,需要自己定義實現即

1 //涉及到堆空間即需進行深拷貝,拷貝構造函數和"="
2     Exception(const Exception& e);
3     Exception& operator =(const Exception& e);

 

 

 

完整代碼如下

Exception.h 

 1 #ifndef _EXCEPTION_H_
 2 #define _EXCEPTION_H_ 
 3 namespace DataStructureLib
 4 {
 5 
 6 class Exception
 7 {
 8 protected:
 9     char*  m_message;
10     char*  m_location;
11 protected:
12     void  init(const char*,const char*,int);//由於三個構造函數中的邏輯很相似,所以可以將相似的部分統一放到一個函數init()
13 public:
14     Exception(const char* message); 
15     Exception(const char* file,int line);
16     Exception(const char* message,const char* file,int line);
17 
18     //涉及到堆空間即需進行深拷貝,拷貝構造函數和"="
19     Exception(const Exception& e);
20     Exception& operator =(const Exception& e);
21 
22     virtual const char* message() const;
23     virtual const char* location() const;
24 
25     virtual ~Exception(void);
26 };
27 #endif
28 }

Exception.cpp 

 1 #include "Exception.h"
 2 #include <cstring>
 3 #include <cstdlib>
 4 
 5 namespace DataStructureLib
 6 {
 7 void Exception::init(const char* message,const char* file,int line)
 8 {
 9     m_message=strdup(message);//這里不能直接使用m_message=message,
10                             //因為message指針指向的數據有可能會在棧、堆、全局區,如果是在棧上,局部變量可能會消失,如果直接使用m_message=message就會不安全    
11     if(file!=NULL)
12     {
13         char sl[16]={0};
14         itoa(line,sl,10);//將line轉為char類型 10代表十進制
15 
16         m_location=static_cast<char* >(malloc(strlen(file)+strlen(sl)+2));//加2表示后面的":"和結束符即“/0”
17         m_location=strcpy(m_location,file);
18         m_location=strcat(m_location,":");
19         m_location=strcat(m_location,sl);
20     }
21 }
22 
23 Exception::    Exception(const char* message)
24 {
25     init(message,NULL,0);
26 }
27 
28 Exception::Exception(const char* file,int line)
29 {
30     init(NULL,file,line);
31 }
32 
33 Exception::Exception(const char* message,const char* file,int line)
34 {
35     init(message,file,line);
36 }
37 
38 Exception::~Exception(void)
39 {
40     
41     free(m_message);
42     free(m_location);
43 }
44 
45 const char* Exception::message() const
46 {
47     return m_message;
48 }
49 
50 const char* Exception::location() const
51 {
52     return m_location;
53 }
54 
55 Exception::Exception(const Exception& e)
56 {
57     m_message=strdup(e.m_message);
58     m_location=strdup(e.m_location);
59 }
60 
61 Exception& Exception::operator =(const Exception& e)
62 {
63     if (this!=&e)
64     {
65         free(m_message);
66         free(m_location);
67 
68         m_message=strdup(e.m_message);
69         m_location=strdup(e.m_location);
70     }
71     return *this;
72 }
73 
74 }

測試:

#include<iostream>

#include "SmartPointer.h"
#include "Exception.h"

using namespace std;
using namespace DataStructureLib;

int main(int argc,char* argv[])
{    
    try
    {
        throw(Exception("test",__FILE__,__LINE__));
    }
    catch (const Exception& e)
    {
        cout<<e.message()<<endl;
        cout<<e.location()<<endl;
    }

    return 0;
} 

 

 

結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM