zoukankan      html  css  js  c++  java
  • 第六十五课、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类派生的

     

  • 相关阅读:
    BZOJ3674:可持久化并查集加强版
    BZOJ3772:精神污染
    BZOJ3932:[CQOI2015]任务查询系统
    BZOJ3123:[SDOI2013]森林
    BZOJ1926:[SDOI2010]粟粟的书架
    029 列表类型内置方法
    02 Python爬虫之盗亦有道
    01 Python爬虫之Requests库入门
    028 字符串类型内置方法
    027 数字类型内置方法
  • 原文地址:https://www.cnblogs.com/gui-lin/p/6384031.html
Copyright © 2011-2022 走看看