C++基础语法:异常处理(三)

前言

      "打牢基础,万事不愁" .C++的基础语法的学习."学以致用,边学边用",编程是实践性很强的技术,在运用中理解,总结.

引入

        在编写程序时,可能会因为程序错误或者编译问题等出现异常,因此设计了异常处理机制来应对.以<C++ Prime Plus> 6th Edition(以下称"本书")内容做参考.C++基础语法:异常处理(二)-CSDN博客是本贴的前一篇

内容概览

        异常特性,exception类,异常和继承,异常注意事项

异常特性

        1>控制权转移 

        本书P629 虽然throw-catch机制类似于函数参数和函数返回机制,但还是有些不同之处。其中之一是函数fun( )中的返回语句将控制权返回到调用fun( )的函数,但throw语句将控制权向上返回到第一个这样的函数:包含能够捕获相应异常的try-catch组合。例如,在程序清单15.12中,当函数 hmeans( )引发异常时,控制权将传递给函数means( );然而,当gmean( ) 引发异常时,控制权将向上传递到main( )。(黑体字是原话)

        ----解读:return语句将控制权返回调用他的函数,而throw语句将控制权返回他使用的catch代码块所在的函数.程序的走向可能因throw()发生改变,不再是main()函数.这通常不会是程序员想看到的情况,看一下程序清单15.12 error5.cpp,mean()的函数定义(本书P628),倒数第三句"throw",在执行完后程序走向转移给了main().因此这个特性只需要注意,不会主动去用.

        2>catch后的形参如果是类对象,类型采用对象的引用类型.

        记住这样用就行.在函数重载中,使用变量作形参和使用变量引用作形参,不构成重载.因此用在异常中catch语句的时候只能二选一,选择引用类型.

        还需要记住的有以下两点:

        1.将引发异常和创建对象组合在一起将更简单.本书P629倒数第二段

        也就是throw后调用异常类的构造函数,写法如: throw problem();   //创建problem对象并抛出

        2.本书P630讲了一种场景:catch后面的异常类之间有继承关系的时候,处理异常函数中从上到下依次是基类对象和派生类对象.catch后面从下往上依次是基类对象和派生类对象.

        原因是基类引用可以接收派生类对象.而派生类引用只能接收派生类对象以及用派生类作基类的派生类对象.

        3>catch后跟(...)表示捕获任何异常 

        用法:放在最后一个catch块中,三个省略号表示任何异常被捕获.

异常特性小结

         第2-1条比较常用,其他用得不多.第1条控制权转移,不要让程序跟着throw走,要回到main()中.第3条捕获任何异常,表示编写程序的人自己都不知道会发生什么,也不太适合.

exception类

         C++异常的主要目的是为设计容错程序提供语言级支持即异常使得在程序设计中包含错误处理功能更容易,以免事后采取一些严格的错 误处理方式。异常的灵活性和相对方便性激励着程序员在条件允许的情 况下在程序设计中加入错误处理功能。总之,异常是这样一种特性:类似于类,可以改变您的编程方式。 较新的C++编译器将异常合并到语言中。例如,为支持该语言, exception头文件(以前为exception.h或except.h)定义了exception类, C++可以把它用作其他异常类的基类。代码可以引发exception异常,也 可以将exception类用作基类。有一个名为what( )的虚拟成员函数,它返回一个字符串,该字符串的特征随实现而异 (黑体字是原话)

        ----解读:提供语言级别的支持,语言内定义了exception类,由#include<exception>导入.如果前面的内容只是"开胃菜",那么这是"正菜"了.因为前面的异常类内容需要自己编写,这里的exception类指出在语言的底层给与支持,可以不用自己写异常类,或者可以继承exception类来表达,这种情况下还可以调用名为"what()"的虚成员函数.        

        如果不想以不同的方式处理这些派生而来的异常,可以在同一个基类处理程序中捕获它们:

        以下是经典代码(可以背下来用的),处理一切异常问题,后面的异常内容可以不看了:)

//本书代码
try{
    ...                    //调用可能产生异常的函数(含throw或者字函数含throw
}
catch(std::exception &e){  //用exception对象抓取异常
    cout<<e.what()<<endl;  //调用what()
}

============================内容分割线==================================== 

        1.除了低头拉车,还要抬头看路.在学习的同时往前往后都看一看.

        是时候反思一下为什么要用异常?什么情况下用异常?

        异常是为了解决被调用的函数可能出错的情况.函数出错的情况是什么?最开始的例子讲了输入参数异常造成逻辑错误是一种,如果程序员编写函数逻辑错误,用try-catch抓取,也看不出来.因此异常处理可以起"流程占位"的作用.对此可以作一个推导:

        把抓取输入异常的两个参数换成"中间结果",即某些函数的返回值,在不知道会不会出错的情况下,推进主程序的编写

        假如要快速搭建一个程序,不管编写的函数有没有问题,先try,完成main()的整个流程,回头再把函数完善.------这是异常的优点

        当然坏处也是显而易见的:第一如果到处都是try,代码难看.另外更主要的是如果一个异常是另一个异常所引起的,不好排查.

        综上所述,尽量让自己熟练写代码,少出错,尽量不用异常处理.前面输入两个参数的异常,可以用以下代码:

//代替异常的代码
int a,b;
while(!(cin>>a>>b&&a+b!=0)){
    cin.clear();
    while(cin.get()!='\n');
    cout<<"请输入两个整数,且不能互为相反数(两个数相加等于0)"
}
....                            //得到两个满足需要的整数,继续程序编写

        2.复习一下类的定义和使用:传入数据(属性),产生逻辑(函数).

        有专门处理异常的类,传入数据作属性,给出异常处理结果.所以类和函数本质上是一样的

============================内容分割线====================================

        空指针和new

          很多代码都是在new在失败时返回空指针时编写的。为处理new的变化,有些编译器提供了一个标记(开关),让用户选择所需的行为。当前,C++标准提供了一种在失败时返回空指针的new

        ----解读:本书明确提到了new分配内存空间的时候容易出错,对于C++而言,用new分配堆空间是常事,所以值得重视,即使不提倡使用异常的情况下.用法:

//本书代码
int *pi=new (std::nothrow) int;
int *pa=new (std::nothrow) int[500];

        以下是经典代码(可以背下来),和程序清单15.13 newexcp.cpp比起来清爽多了

//本书代码
#include<new>
#include<cstdlib>        //for exit(),EXIT_FAILURE

Big *pb=new (std::nothrow) Big[10000];    //16亿字节
if(pb==0){
    cout<<"Could not allocate memory.Bye.\n";
    exit(EXIT_FAILURE);
}

        含义:如果分配空间失败,退出

小结

        对异常的一些理解

        异常的内容可以深入挖掘,但也可以减减负,等用到的时候再深入

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jllws1

你的鼓励是我创作的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值