65、c++异常处理(下)

catch语句块中可以抛出异常:

try{func}

catch(int i){throw i;}  -->将捕获的异常重写抛出

catch(...){throw;}  //没有名字,直接抛出

catch中抛出的异常需要外层try...catch...捕获

为啥要重新抛出异常:catch中捕获的异常可以被重新解释后抛出。

工程开发中使用这样的方式统一异常类型:

第三方库(void func(int i);//异常类型为int*)<----私有库(void myfunc(int i) //异常类型为exception)

工程开发:通过调用myfunc获得func函数的功能和统一的异常信息--->调用私有库

如果调用私有库没有的功能,要调用第三方库,myfunc用来封装直接调用第三方库中的函数,在myfunc捕获func抛出的异常,重新解释为我们自己的异常,然后抛出我们自己的异常,用catch抛出异常统一异常的类型。

#include <iostream>
#include <string>
using namespace std;
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;
    }
}
/*下边的func
    假设: 当前的函数式第三方库中的函数,因此,我们无法修改源代码
    
    函数名: 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 << "Run func..." << endl;

}

//我们自己的函数重新解释func

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(int argc, char *argv[])
{
    // Demo();    
    try
    {
        MyFunc(11);
    }
    catch(const char* cs)     //上边的 “Timeout Exception”
    {
        cout << "Exception Info: " << cs << endl;
    }    
    return 0;
}

异常处理与函数的区别:函数处理会有默认的类型转换,而异常处理没有类型转换,严格匹配。

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

对于类类型异常的,匹配依旧是至上而下严格匹配。赋值兼容性原则在异常匹配中依然适用。

一般而言,匹配子类异常的catch放在上部,匹配父类异常的catch放在下部。子类异常对象可以被父类catch语句抓住。

在工程中会定义一系列的异常类,每个类代表工程中可能出现的一种异常类型,代码复用时可能需要重解释不同的异常类,在定义catch语句块时推荐使用引用作为参数(类对象可以避开拷贝构造,提高效率)。

#include <iostream>
#include <string>
using namespace std;
class Base
{
};
class Exception : public Base
{
    int m_id;  //异常id
    string m_desc;  //异常描述信息
public:
    Exception(int id, string desc)
    {
        m_id = id;
        m_desc = desc;
    }
    
    int id() 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 << "Run func..." << endl;
}


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(int argc, char *argv[])
{
    try
    {
        MyFunc(11);
    }
    catch(const Exception& e)  //有const ,成员函数也必须是const成员函数
    {
        cout << "Exception Info: " << endl;
        cout << "   ID: " << e.id() << endl;
        cout << "   Description: " << e.description() << endl;
    }
    catch(const Base& e)  //exception对象类型是base对象的子类,子类对象可以当作父类对象使用,必须放到下边
    {
        cout << "catch(const Base& e)" << endl;
    }
    return 0;
}

3、c++标准库中提供了实用异常类族,标准库中的异常都是从exception类派生的,exception类有两个主要的分支

logic_error:常用于程序中的可避免逻辑错误。

runtime_error:常用于程序中无法避免的恶性错误。

数组类优化:

#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
    {
        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
    {
        throw out_of_range("T Array<T, N>::operator[] (int index) const"); //标准库中的异常
    }

}

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

#endif


#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); 
    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() const;
    ~HeapArray();

};

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

}

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 length) 
{
    HeapArray<T>* ret = new HeapArray<T>(length);
    
    if( !(ret && ret->construct()) ) 
    {
        delete ret;
        ret = 0;
    }
        
    return ret;

}

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 < 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 < length());
    
    if( ret )
    {
        m_pointer[index] = value;
    }    
    return ret;
}
//优化
template
< typename T >
T& HeapArray<T>::operator [] (int index)
{
    if( (0 <= index) && (index < 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 < 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()
{
    return *this;
}

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

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

#endif


#include <iostream>
#include <string>
#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<a.length(); i++)
    {
        cout << a[i] << endl;
    }
}
void TestHeapArray()
{
    HeapArray<double>* pa = HeapArray<double>::NewInstance(5);    
    if( pa != NULL )
    {
        HeapArray<double>& array = pa->self();        
        for(int i=0; i<array.length(); i++)
        {
            array[i] = i;
        }            
        for(int i=0; i<array.length(); i++)
        {
            cout << array[i] << endl;
        }
    }    
    delete pa;
}
int main(int argc, char *argv[])
{   
    try
    {
        TestArray();        
        cout << endl;       
        TestHeapArray();
    }
    catch(...)
    {
        cout << "Exception" << endl;
    }    
    return 0;
}

catch语句块中可以抛出异常,异常类型可以是自定义类型,赋值兼容性原则在异常匹配中依然适用,标准库的异常都是从exception类派生的。

猜你喜欢

转载自blog.csdn.net/ws857707645/article/details/80292543