第六十五课、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类派生的

 

时间: 2024-11-06 11:41:11

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

第六十五课 二叉树中属性操作的实现

递归功能函数: 1 int count(BTreeNode<T>* node) const 2 { 3 return (node != NULL) ? (count(node->left) + count(node->right) + 1) : 0; 4 } 功能函数如下: 1 int height(BTreeNode<T>* node) const 2 { 3 int ret = 0; 4 5 if( node != NULL ) 6 { 7 int lh = hei

六十五、SAP中通过BREAK-POINT下断点,进行调试

一.代码如下,有2个断点的按钮,可以可以写入BREAK-POINT人工断点 二.运行之后,程序会被断下来, 四个执行按钮,意思分别为:单步进入子程序,单步不进入子程序,返回外面,执行到断点处 三.我们双击变量中的ITAB5 四.在结构中可以看到他是由2个成员组成的结构体 五.我们双击内表图标 六.可以看到,此处为一个内表 七.遇到问题要沉着冷静,多调试. 原文地址:https://www.cnblogs.com/tianpan2019/p/11229187.html

JAVA学习第六十五课 — 正則表達式

正則表達式:主要应用于操作字符串.通过一些特定的符号来体现 举例: QQ号的校验 6~9位.0不得开头.必须是数字 String类中有matches方法 matches(String regex) 告知此字符串是否匹配给定的正則表達式. regex,就是给定的正則表達式 public static void checkQQ() { //第一位是数字1-9,第二位以后是0-9,除去第一位数剩下数字位数范围是5到8位 String regex = "[1-9][0-9]{5,8}";//正

剑指offer(六十五)之矩阵中的路径

题目描述 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径.路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子.如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子. 例如 a b c e s f c s a d e e 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子. 代码: /*

JAVA学习第六十五课 — 正则表达式

正则表达式:主要应用于操作字符串,通过一些特定的符号来体现 举例: QQ号的校验 6~9位,0不得开头,必须是数字 String类中有matches方法 matches(String regex) 告知此字符串是否匹配给定的正则表达式. regex,就是给定的正则表达式 public static void checkQQ() { //第一位是数字1-9,第二位以后是0-9,除去第一位数剩下数字位数范围是5到8位 String regex = "[1-9][0-9]{5,8}";//正

第六十四课 二叉树中结点的删除与清除

BTree.h中添加删除操作: 1 #ifndef BTREE_H 2 #define BTREE_H 3 4 #include "Tree.h" 5 #include "BTreeNode.h" 6 #include "Exception.h" 7 #include "LinkQueue.h" 8 9 namespace DTLib 10 { 11 12 template < typename T > 13 cl

QT开发(六十五)——QT样式表编程实例

QT开发(六十五)--QT样式表编程实例 一.QComboBox组合框样式定制 1.基本定义 QComboBox  {     border: 1px solid gray;     border-radius: 3px;     padding: 1px 2px 1px 2px;  # 针对于组合框中的文本内容     min-width: 9em;   # 组合框的最小宽度 } QComboBox::drop-down {     subcontrol-origin: padding;   

NeHe OpenGL教程 第三十五课:播放AVI

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十五课:播放AVI 在OpenGL中播放AVI: 在OpenGL中如何播放AVI呢?利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错.你可以试试. 首先我得说我非常喜欢这一章节.Jonat

NeHe OpenGL教程 第二十五课:变形

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十五课:变形 变形和从文件中加载3D物体: 在这一课中,你将学会如何从文件加载3D模型,并且平滑的从一个模型变换为另一个模型. 欢迎来到这激动人心的一课,在这一课里,我们将介绍模型的变形.需要注意的是各个模型必须要有相同的顶点,