|  | 
 
| 
本帖最后由 moc 于 2018-9-13 22:12 编辑
x
马上注册,结交更多好友,享用更多功能^_^您需要 登录 才可以下载或查看,没有账号?立即注册  
 1、异常的简介
 异常是程序在执行期间产生的问题,提供的一种转移程序控制权的机制,与函数机制独立和互补。
 函数是一种以站结构展开的上下函数衔接的程序控制系统,异常是另一种控制结构,它依附于栈的结构,却可以同时设置多个异常作为网捕条件,以类型匹配在栈机制中跳跃回馈。
 C++ 异常处理涉及到三个关键字:try、catch、throw。
 异常处理的基本思想:
 
   1. C++的异常处理机制使得异常的引发和异常处理不必在一个函数中,这样底层函数可以着重解决具体的问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计针对不同类型的异常处理。
 2. 异常是专门针对抽象编程的一系列错误处理,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法跳跃,但错误处理机制遇到错误可以转到若干级之上进行错误处理。
 
   3. 异常超脱于函数机制,决定了其对函数的跨越式回跳。即异常跨越函数。
 2、异常的基本语法
 
 复制代码throw  表达式;    // 抛出异常
//捕获并处理异常
try
{
   // 保护代码
}catch( ExceptionName e1 )
{
   // catch 块
}catch( ExceptionName e2 )
{
   // catch 块
}catch( ... )  //其他未知异常
{
   // catch 块
}
1.  若有异常则通过throw操作创建一个异常对象并抛掷;
 2.  将可能抛出的异常的程序嵌在try块中,try块内为保护代码。
 3.  catch子句在try之后,按顺序进行检查,匹配捕获并进行异常处理(或继续抛异常);
 4.  try语句没有发生异常,则跳过catch子句继续向下执行;
 5.  如果没有找到匹配的catch,即抛出的异常无人接受,激发最后一道防线,terminate函数(可修改),该函数引起运行终止和abort函数。
 6. 类的构造函数无返回类型,不能通过返回值报告运行状态,可通过异常解决。
 7. 异常机制与函数机制互不干涉,异常的捕捉方式是基于类型匹配,捕捉相当于函数返回类型匹配,而不是函数参数匹配,所以捕捉不用考虑一个抛掷中的多种数据类型匹配问题。
 8. 异常匹配严格按照类型匹配。匹配苛刻程度与模板一样,不允许隐式类型转换。
 
 复制代码void divide(int x, int y)
{
        if (y == 0)    // 0为除数 
        {
                throw x;   // 抛出 int类型  异常
        }
        cout << "Divide结果:" << x / y << endl;
}
void myDivide0(int x, int y)
{
        divide(x, y);
}
// 发生的异常必须在函数中处理,否者会产生函数中断
int main()
{
        try
        {
                myDivide0(10, 2);
                myDivide0(123, 0);
        }
        catch (int e)   // 捕获int型异常
        {
                cout << e << "被零除" << endl;
        }
        catch (...)   // 捕获漏网之鱼
        {
                cout << "其他未知的异常!" << endl;
                cout << "我接受了异常,但我没有处理,我继续往外扔";
                throw;
        }
        system("pause");
        return 0;
}
3、栈解旋
 异常抛出后,从进入try块起到异常被抛出前,这期间在栈上的构造的所有对象都会被析构,析构的顺序和构造的顺序相反,这一过程即  栈解旋 。
 函数抛出异常限定,可以在定义函数之后加throw说明。
 
 复制代码class Test
{
public:
        Test(int a = 0, int b = 0)
        {
                this->a = a;
                this->b = b;
                cout << "构造函数do\n";
        }
        ~Test()
        {
                cout << "析构函数do\n";
        }
private:
        int a;
        int b;
};
void myDivide()
{
        Test t1(1, 2), tr2(3, 4);  // 测试t1,t2的析构顺序
        cout << "myDivide...发生异常\n";
        throw Test();
}
void myDivide12() throw (int , char, char*)  //该函数只能抛出int,char,char*类型的异常
{
        throw Test();
}
void myDivide2() throw()  // 该函数不会抛出任何异常
{
        throw Test();  // 非要抛出时有警告。
}
int main() 
{
        try
        {
                myDivide();
        }
        catch (int a)
        {
                cout << "int类型 异常\n";
        }
        catch (...)
        {
                cout << "未知 异常\n";
        }
        system("pause");
        return 0;
}
4、异常变量的生命周期
 throw “aaa”;  是抛出的char*类型。
 对于抛出类对象:
 1.  如果  接受异常的时候  使用一个异常变量,则执行copy构造函数构造异常变量;
 2.  使用引用的话  会直接使用throw时候的那个对象
 3.  使用指针接的话,如果抛出时不new一个对象的话,会形成参野指针;
 最终结论:类对象发生异常时,使用引用比较合适
 
 5、异常的层次结构
 即继承在异常中的应用
 对于同一种类型的异常;异常派生,按引用传递异常。
 6、C++ 标准的异常
 C++ 提供了一系列标准的异常,定义在 <exception> 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:
 
   传送门
 
 
 | 
 |