码迷,mamicode.com
首页 > 其他好文 > 详细

【共读Primer】39.<5.6>try语句块和异常处理 Page172

时间:2018-08-31 10:50:38      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:一个   退出   dex   int   \n   输入   row   main   反向   

异常,程序检测到当前的情况超出它的处理能力的时候将跑出异常。

比如常见的异常有除零问题,数据库连接丢失输入需要数字的情况下给出了字母输入

典型的异常处理包含以下几个部分: try块,将可能发生异常的语句置于try块中,catch 括号中的参数时一个异常类型,通过类型的不同来判断不同的异常

try{
    program-statements
}catch(exception-declaration){
    handler-statments  
}catch(exception-declaration){
    handler-statments  
}

异常并不是只能由系统自己触发,也可以人为的抛出异常

throw runtime_error("this is a throw error")

异常处理的一个基本目标是尽量减少程序的非正常退出,并尽可能的修复运行异常

而try语句块也为我们提供了这样的可能

先看一下这段代码,我们从用户输入中接收到两本书的销售信息,然后判断,是否相同,相同则相加,否则抛弃数据。

但是这段代码在不相同的情况下并没有完成任务就退出了,只给用户一个无关痛痒的提示。

Sales_item item1, item2;
cin >> item1 >> item2;

if(item1.isbn() == item2.isbn())
{
    cout << item1 + item2 << endl;
    return 0
}
else
{
    cerr << "Data must refer to same ISBN" << endl;
    return -1;
}

下面这段代码,将在输入错误的情况下抛出一个异常,抛出异常的好处是在调用处,必须处理它,否则程序将异常退出。

那么光有这一段抛出异常显然是不行的,我们要达到目的还需要捕获这个异常

// 将以上代码改为一个抛出异常的版本

Sales_item item1, item2;
cin >> item1 >> item2;

if(item1.isbn() != item2.isbn())
{
    throw runtime_error("Data must refer to same ISBN");
}
cout << item1 + item2 << endl;

根据捕获异常的要求我们将代码升级成以下样式

// 但是以上部分如果输入的ISBN不同程序就将异常终止,
// 这个时候我们需要try块来进行捕获
Sales_item item1, item2;
while(cin >> item1 >> item2)
{
    try
    {
        if(item1.isbn() != item2.isbn())
        {
            throw runtime_error("Data must refer to same ISBN");
        }
        cout << item1 + item2 << endl; // 匹配时运算并输出
        break;
    }
    catch(runtime_error err)
    { // 提醒用户两个ISBN必须一致,询问是否重新输入
        cout << err.what() << "\nTyr Again? Enter y or n." << endl;
        char c;
        cin >> c;
        if(!cin || c == n)
            break;
    }
}

 

这样异常可以被捕获,就不会对程序的运行造成致命的威胁了。

异常抛出后的搜索顺序是从入口函数开始的调用关系到当前运行代码一层层的反向搜索上去。

直到找到异常处理的catch块,或者找到入口main函数还未找到,则程序交给名称是terminate的标准函数。

这个函数的行为与系统相关,但是一般的原则是终止当前程序并异常退出。

标准库里的异常类型

共有4个头文件定义了异常类型

exception头文件、stdexcept头文件、new头文件(bad_alloc)、type_info头文件(bad_cast)

本节中使用到的runtime_error属于stdexcept中

 

 技术分享图片

 

 技术分享图片

 下面贴出全部代码供大家自行编译调试

39.cpp

//39.cpp
#include <iostream>
#include "Sales_item.h"

using std::cin;
using std::cout;
using std::endl;
using std::runtime_error;

int main()
{
    Sales_item item1, item2;
    while(cin >> item1 >> item2)
    {
        try
        {
            if(item1.ISBN() != item2.ISBN())
            {
                throw runtime_error("Data must refer to same ISBN");
            }
            cout << item1 + item2 << endl;
            break;
        }
        catch(runtime_error err)
        { // 提醒用户两个ISBN必须一致,询问是否重新输入
            cout << err.what() << "\nTyr Again? Enter y or n." << endl;
            char c;
            cin >> c;
            if(!cin || c == n)
                break;
        }
    }
}

Sales_item.h

// Sales_item.h
#ifndef SALESITEM_H
#define SALESITEM_H
#include <iostream>
#include <string>

class Sales_item{
public:
    Sales_item(const std::string &book):isbn(book),units_sold(0),revenue(0.0){}
    Sales_item(std::istream &is){ is >> *this;}
    friend std::istream& operator>>(std::istream &,Sales_item &);
    friend std::ostream& operator<<(std::ostream &,const Sales_item &);
public:
    Sales_item & operator+=(const Sales_item&);  
public:
    double avg_price() const;
    bool same_isbn(const Sales_item &rhs)const{
    return isbn == rhs.isbn;
    }
    std::string ISBN(){return isbn;}
    Sales_item():units_sold(0),revenue(0.0){}
public:
    std::string isbn;
    unsigned units_sold;
    double revenue;
};

using std::istream;
using std::ostream;
Sales_item operator+(const Sales_item &,const Sales_item &);

inline bool operator==(const Sales_item &lhs,const Sales_item &rhs){
    return lhs.units_sold == rhs.units_sold && lhs.revenue == rhs.revenue && lhs.same_isbn(rhs);  
}

inline bool operator!=(const Sales_item &lhs,const Sales_item &rhs){
    return !(lhs == rhs);
}

inline Sales_item & Sales_item::operator +=(const Sales_item &rhs){
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}

inline Sales_item operator+(const Sales_item &lhs,const Sales_item &rhs){
    Sales_item ret(lhs);
    ret += rhs;
    return ret;
}

inline istream& operator>>(istream &in,Sales_item &s){
    double price;
    in >> s.isbn >> s.units_sold >> price;
    if(in)
        s.revenue = s.units_sold * price;
    else
        s = Sales_item();
    return in;
}

inline ostream& operator<<(ostream &out,const Sales_item &s){
    out << s.isbn << "\t" <<s.units_sold << "\t" << s.revenue << "\t" << s.avg_price();
    return out;
}

inline double Sales_item::avg_price() const{
    if(units_sold)
        return revenue/units_sold;
    else
        return 0;
}
#endif // SALESITEM_H

 

【共读Primer】39.<5.6>try语句块和异常处理 Page172

标签:一个   退出   dex   int   \n   输入   row   main   反向   

原文地址:https://www.cnblogs.com/ChattyKu/p/9563888.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!