首页IT科技c++模板教程(c++学习笔记——模板和IO(二))

c++模板教程(c++学习笔记——模板和IO(二))

时间2025-06-20 22:35:09分类IT科技浏览5012
导读:C++异常 前言:...

C++异常

前言:

异常处理就是处理程序中的错误              。所谓错误是指在程序运行的过程中发生的一些异常事件(如:除0溢出              ,数组下标越界                    ,所要读取的文件不存在      ,空指针       ,内存不足等等)

在对C语言的学习中                    ,我们常常对错误的处理围绕着两种方法:一种是使用整型的返回值标识错误;二是使用errno宏(可以简单的理解为一个全局整型变量)去记录错误                    。

但这两种方法最大的缺陷就是会出现不一致问题      。例如有些函数返回1表示成功             ,返回0标识错误;而有些函数返回0标识成功       ,返回非0表示错误       。还有一个缺陷是函数的返回值只有一个                    ,你通过函数的返回值表示错误代码             ,那么函数就不能返回其他的值                    。

C++相比C语言在异常处理上有哪些优势呢?

我们可先看看下面异常语法的代码再进行总结             。

//异常的基本语法 int func(int a, int b) { if (b == 0) { //第二步: throw 10; //抛出一个int类型的异常 } return a / b; } void test() { int a = 10; int b = 0; //把有可能出现异常的代码块放到try中 try { func(a, b); //第一步 } catch (int) //第三步 { cout << "接收一个int类型的异常" << endl; } }

回到上面的问题

函数的返回值可以忽略,但异常不可忽略       。如果程序出现异常                    ,但是没有被捕获                   ,程序就会终止,这多少会促使程序员开发出来的程序更健壮一点                    。而如果使用C语言的error宏或者函数返回值              ,调用者都有可能忘记检查                   ,从而没有对错误进行处理      ,结果造成程序莫名其面的终止或出现错误的结果             。 整型返回值没有任何语义信息。而异常却包含语义信息              ,有时你从类名就能够体现出来                    。 整型返回值缺乏相关的上下文信息                   。异常作为一个类                    ,可以拥有自己的成员      ,这些成员就可以传递足够的信息。 异常处理可以在调用跳级              。这是一个代码编写时的问题:假设在有多个函数的调用栈中出现了某个错误       ,使用整型返回码要求你在每一级函数中都要进行处理                   。而使用异常处理的栈展开机制                    ,只需要在一处进行处理就可以了             ,不需要每级函数都处理      。

异常具有严格的类型匹配

异常机制和函数机制互不干涉,但是捕捉方式是通过严格类型匹配              。

int func(int a, int b) { if (b == 0) { throw 20.2f; } return a / b; } void test() { int a = 10; int b = 0; try { func(a, b); } catch (double s) { cout << "接收一个double类型的异常" << endl; } catch (char) { cout << "接收一个char类型的异常" << endl; } catch (...) //接收其他类型的异常 { cout << "接收一个其他类型的异常" << endl; } }

栈解旋(unwinding)

异常被抛出后       ,从进入try块起                    ,到异常被抛掷前             ,这期间在栈上构造的所有对象,都会被自动析构                    。析构的顺序与构造的顺序相反                    ,这一过程称为栈的解旋(unwinding).

class Maker { public: Maker() { cout << "Maker的构造" << endl; } Maker(const Maker& m) { cout << "Maker的拷贝构造" << endl; } ~Maker() { cout << "Maker的析构" << endl; } }; void func() { //在抛出异常的函数中                   ,如果抛出异常之后,但函数没有结束              ,这时                   ,栈上申请的对象都会被释放 //这就叫栈解旋 Maker m; throw m;//这个m是Maker m拷贝构造的 cout << "func函数结束" << endl; } void test() { try { func(); cout << "func()代码后" << endl; } catch (Maker) { cout << "接收一个Maker类型的异常" << endl; } }

运行结果:

异常接口声明

为了加强程序的可读性      ,可以在函数声明中列出可能抛出异常的所有类型              ,例如:void func() throw(A,B,C);这个函数func能够且只能抛出类型A,B,C及其子类型的异常      。 如果在函数声明中没有包含异常接口声明                    ,则此函数可以抛任何类型的异常      ,例如:void func() 一个不抛任何类型异常的函数可声明为:void func() throw() 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexcepted函数会被调用       ,该函数默认行为调用terminate函数中断程序       。 void func() throw(int, char) //只允许抛出 int 或者 char异常 { throw 10; //抛出一个double类型的异常 } void test() { try { func(); } catch (int) { cout << "抛出一个int型的异常"; } catch (...) { cout << "抛出一个其他型的异常"; } }

运行结果:

异常变量周期

产生三个对象

class Maker { public: Maker() { cout << "Maker的构造" << endl; } Maker(const Maker& m) { cout << "Maker的拷贝构造" << endl; } ~Maker() { cout << "Maker的析构" << endl; } }; //产生三个对象 void func1() { Maker m;//第一个对象                    ,在异常接收前被释放 throw m;//第二个对象             ,是第一个对象拷贝过来的 } void test01() { try { func1(); } catch (Maker m1)//第三个对象       ,是第二个对象拷贝过来的 { cout << "接收一个Maker类型的异常" << endl; //第二个和第三个对象在catch结束时释放 } }

产生两个对象

void func2() { //第一个对象 throw Maker();//匿名对象 } void test02() { try { func2(); } catch (Maker m1)//第二个对象 { cout << "接收一个Maker类型的异常" << endl; //第一个和第二个对象在catch结束时释放 } }

产生一个对象

void func3() //常用这种方式 { throw Maker();//匿名对象 } void test03() { try { func3(); } catch (Maker& m1) { cout << "接收一个Maker类型的异常" << endl; } }

异常的多态使用

//异常的基类 class Father { public: virtual void printM() { } }; //1             、有继承 class SonNULL :public Father { public: virtual void printM() //2                    、重写父类的虚函数 { cout << "空指针的异常" << endl; } }; class SonOut :public Father { public: virtual void printM() { cout << "越位溢出" << endl; } }; void func(int a,int b) { if (a == 0) { throw SonNULL(); } if (b == 0) { throw SonOut(); } } void test() { int a = 0; int b = 10; try { func(a, b); } catch (Father& f) //3       、父类引用指向子类对象 { f.printM(); } }

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
dispatch note(dispatchEvent解决重叠元素响应事件示例详解)