首页 > 代码库 > 第六十五课、c++中的异常处理(下)

第六十五课、c++中的异常处理(下)

  一、catch语句中可以抛出异常

(1)、catch语句中抛出的异常需要外层的try...catch...捕获

技术分享

(1)、catch中捕获的异常可以被重新解释后抛出

(2)、工程中使用这样的方式统一异常类型

 技术分享

#include <iostream>
using namespace std;

//演示在catch块中可以抛出异常
void Demo()
{
    try
    {
        try
        {
            throw c;
        }
        catch(int i)
        {
            cout << "Inner:catch(int i)" << endl;
            throw i;  //重新抛出异常
        }
        catch(...)
        {
            cout << "Inner:catch(...)" << endl;
            throw;  //抛出所有类型的异常
        }        
    }catch(...)
    {
        cout << "Outer:catch(...)" << endl;
    }
}

/*
    假设:当前的函数是第三方库中的函数。因此,我们无法修改源代码
    
    函数名: void func(int i)
    抛出异常的类型:int
                        -1 ==> 参数异常
                        -2 ==> 运行异常
                        -3 ==> 超时异常
*/
void func(int i)
{
    if ( i < 0 )
    {
        throw -1;
    }
    
    if ( i > 100 )
    {
        throw -2;
    }
    
    if ( i == 11)
    {
        throw -3;
    }
    
    //正常运时时
    cout << "Call func(int i)" << endl;
}

//以下是我们的私有库,当中使用到了第3方的库,这里需要将第3方库的
//异常类型统一成我们的异常信息格式
void MyFunc( int i)
{
    try
    {
        func(i);
    }
    catch(int i)
    {
        switch(i)
        {
        case -1:
            throw "Invalid Parameter";//重新解释后抛出
            break;
        case -2:
            throw "Runtime Exception";
            break;
        case -3:
            throw "Timeout Exception";
            break;
        }
    }
}

int main()
{
    Demo();
    
    cout << endl;
    
    try
    {
        MyFunc(11);
    }
    catch(const char* cs)
    {
        cout << "Exception info: " << cs << endl; 
    }
    return 0;
};
/*输出结果:
Inner:catch(...)
Outer:catch(...)

Exception info: Timeout Exception
*/

二、类类型中的异常

 1、异常的类型可以是自定义的类类型

2、对于类类型的异常匹配依旧是自上而下的严格匹配

3、赋值兼容性原则在匹配中依然适用

4、一般而言

(1)、匹配子类异常的catch放在上部

(2)、匹配父类异常的catch放在下部

5、工程中的应用

(1)、在工程中会定义一系列的异常类

(2)、每个类代表工程中可能出现的一种异常类型

(3)、代码复用时可能需要重解释不同的异常类

(4)、在定义catch语句块时推荐使用引用作为参数(减少拷贝构造的调用以提高效率)

 

#include <iostream>
#include <string>

using namespace std;

class Base
{
};

class Exception: public Base
{
    int m_id;
    string m_desc;
public:
    Exception(int id, string desc)
    {
        m_id = id;
        m_desc = desc;
    }
    
    int id() const  //考虑const Exception对象时,函数加const
    {
        return m_id;
    }
    
    string description() const
    {
        return m_desc;
    }
};

/*
    假设:当前的函数是第三方库中的函数。因此,我们无法修改源代码
    
    函数名: void func(int i)
    抛出异常的类型:int
                        -1 ==> 参数异常
                        -2 ==> 运行异常
                        -3 ==> 超时异常
*/
void func(int i)
{
    if ( i < 0 )
    {
        throw -1;
    }
    
    if ( i > 100 )
    {
        throw -2;
    }
    
    if ( i == 11)
    {
        throw -3;
    }
    
    //正常运时时
    cout << "Call func(int i)" << endl;
}


//以下是我们的私有库,当中使用到了第3方的库,这里需要将第3方库的
//异常类型统一成我们的异常信息格式
void MyFunc( int i)
{
    try
    {
        func(i);
    }
    catch(int i)
    {
        switch(i)
        {
        case -1:
            throw Exception(-1, "Invalid Parameter");
            break;
        case -2:
            throw Exception(-2, "Runtime Exception");
            break;
        case -3:
            throw Exception(-3, "Timeout Exception");
            break;
        }
    }
}

int main()
{      
    try
    {
        MyFunc(11);
    }
    catch(const Exception& e) //注意使用引用以防止拷贝,提高效率
    {
        cout << "Exception info: " << endl; 
        cout << "     ID: " << e.id() << endl;
        cout << "     Description: " << e.description() << endl;
    }
    catch(const Base& e)  //父类异常放下部,否则根据赋值兼容性原则,父类会首先捕获异常
    {
        cout << "catch(const Base& e)" << endl;
    }
    return 0;
};
/*输出结果:
Exception info:
     ID: -3
     Description: Timeout Exception
*/

三、标准库中的异常

1、c++标准库中提供了实用异常类族

2、标准库中的异常都是从exception类派生的

3、exception类有两个主要的分支

(1)、logic_error:常用于程序中的可避免逻辑错误

(2)、runtime_error:常用于程序中的无法避免的恶性错误

技术分享

//Array.h

#ifndef _ARRAY_H_
#define _ARRAY_H_

#include <stdexcept>  //引入异常类
using namespace std;

template <typename T, int N>
class Array
{
    T m_array[N];
public:
    int length() const;
    bool set(int index, T value);
    bool get(int index, T& value);
    T& operator[](int index);
    T operator[](int index) const;
    virtual ~Array();
};

template < typename T, int N>
int Array<T, N>::length() const
{
    return N;
}

template < typename T, int N>
bool Array<T, N>::set(int index, T value)
{
    bool ret = (0 <= index) && (index < N);
    
    if (ret)
    {
        m_array[index] = value;
    }
    
    return ret;
}

template < typename T, int N>
bool Array<T, N>::get(int index, T& value)
{
    bool ret = (0 <= index) && (index < N);
    
    if (ret)
    {
        value = m_array[index];
    }
    
    return ret;
}

template < typename T, int N>
T& Array<T, N>::operator[](int index)
{   
    if((0 <= index) && (index < N))
    {
        return m_array[index];
    }
    else
    {
        //out_of_range是标准库中的异常类
        throw out_of_range("T& Array<T, N>::operator[](int index)");  //参数为抛出的异常信息 
    }
}

template < typename T, int N>
T Array<T, N>::operator[](int index) const
{    
    if((0 <= index) && (index < N))
    {
        return m_array[index];
    }
    else
    {
        //out_of_range是标准库中的异常类
        throw out_of_range("T Array<T, N>::operator[](int index) const");   
    }
}

template < typename T, int N>
Array<T, N>::~Array()
{    
}

#endif

//HeapArray.h

#ifndef _HEAPARRAY_H_
#define _HEAPARRAY_H_

#include <stdexcept>  //引入异常类
using namespace std;

template < typename T>
class HeapArray
{
private:
    int m_length;
    T* m_pointer;
    
    HeapArray(int len);
    HeapArray(const HeapArray<T>& obj);
    bool construct();
public:
    static HeapArray<T>* NewInstance(int length);
    static void ReleaseInstance(const HeapArray<T>* pointer);
    int length() const;
    bool get(int index, T& value);
    bool set(int index, T value);
    T& operator[](int index);
    T operator[](int index) const;  //与上面函数构成重载关系
    HeapArray<T>& self() const;
    HeapArray<T>& self();           //与上面函数构成重载关系
    ~HeapArray();
};

template <typename T>
HeapArray<T>::HeapArray(int len)
{
    m_length = len;
}

template <typename T>
HeapArray<T>::HeapArray(const HeapArray<T>& obj)
{
    m_pointer = obj.m_pointer;
    m_length = obj.m_length;
}

template <typename T>
bool HeapArray<T>::construct()
{
    m_pointer = new T[m_length];
    
    return m_pointer != NULL;
}

template <typename T>
HeapArray<T>* HeapArray<T>::NewInstance(int len)
{
    HeapArray<T>* ret = new HeapArray<T>(len);
    
    if (!(ret && ret->construct()))
    {
        delete ret;
        ret = 0;
    }
    
    return ret;  
}

template <typename T>
void HeapArray<T>::ReleaseInstance(const HeapArray<T>* pointer)
{
    delete pointer;
}

template <typename T>
int HeapArray<T>::length() const
{
   return m_length;
}

template <typename T>
bool HeapArray<T>::get(int index, T& value)
{
    bool ret = ((0 <= index)&&(index < m_length));
    
    if(ret)
    {
        value = m_pointer[index];
    }
    
    return ret;
}

template <typename T>
bool HeapArray<T>::set(int index, T value)
{
    bool ret = ((0 <= index)&&(index < m_length));
    
    if(ret)
    {
        m_pointer[index] = value ;
    }
    
    return ret;
}

template <typename T>
T& HeapArray<T>::operator[](int index)
{  
    if((0 <= index)&&(index < m_length))
    {
        return m_pointer[index];        
    }
    else
    {
        throw out_of_range("T& HeapArray<T>::operator[](int index)");
    }
}

template <typename T>
T HeapArray<T>::operator[](int index) const
{  
    if((0 <= index)&&(index < m_length))
    {
        return m_pointer[index];        
    }
    else
    {
        throw out_of_range("T HeapArray<T>::operator[](int index) const");
    }
}

template <typename T>
HeapArray<T>& HeapArray<T>::self() const
{  
    return *this;
}

template <typename T>
HeapArray<T>& HeapArray<T>::self()
{  
    return *this;
}

template <typename T>
HeapArray<T>::~HeapArray()
{  
    delete[] m_pointer;
}

#endif

//main.cpp

#include <iostream>
#include <string>
#include <memory>  //for auto_ptr
#include "Array.h"
#include "HeapArray.h"
using namespace std;

void TestArray()
{
    Array<int, 5> a;
    
    for(int i=0; i<a.length(); i++)
    {
        a[i] = i;   
    }
    
    for (int i=0; i<10; i++)
    {
        cout << a[i] << endl;
    }
}

void TestHeapArray()
{
    //使用智能指针,目的是自动释放堆空间
    auto_ptr< HeapArray<double> > pa(HeapArray<double>::NewInstance(5));
    
    if(pa.get() != NULL)
    {
        HeapArray<double>& array = pa->self();
        
        for(int i=0; i<array.length(); i++)
        {
            array[i] = i;
        }
        
        for (int i=0; i<10; i++)
        {
            cout << array[i] << endl;
        }          
    }         
}

int main()
{   //试验1:观察异常出错的信息
    TestArray();
       
    cout << endl;
       
    TestHeapArray();   

    //试验2: 观察异常出错的信息   
    // try
    // {
       // TestArray();
       
       // cout << endl;
       
       // TestHeapArray();
    // }
    // catch(...)
    // {
       // cout << "Exception" << endl;
    // }
    
    return 0;
};

四、小结

(1)、catch语句块中可以抛出异常

(2)、异常的类型是可以自定义的类类型

(3)、赋值兼容性原则在异常匹配中依然适用

(4)、标准库中的异常都是从exception类派生的

 

 

第六十五课、c++中的异常处理(下)