【c++思维导图与代码示例】11 异常处理机制

【c++思维导图与代码示例】11 异常处理机制

思维导图:

在这里插入图片描述

代码示例:

  • 示例1:
/*************************************************
**
**Description: 例:处理除数为零的异常
异常处理的基本思想:
在引发异常的模块中,可能是不处理异常的,比如,某一个函数H在运行期间,可能发生了环境或者用户使用的异常故障,导致计算不能继续下去,
函数H可以并不处理这个异常,谁调用了它,就将这个异常抛送给这个调用者,这个调用者可以处理异常,也可以继续向上反馈异常,直到某一级别,专门用来捕获处理异常的层级。

异常接口声明:
• 一个函数显式声明可能抛出的异常,有利于函数的调用者为异常处理做好准备
• 可以在函数的声明中列出这个函数可能抛掷的所有异常类型。
• 例如:void fun() throw(A,B,C,D);
• 若无异常接口声明,则此函数可以抛掷任何类型的异常。
• 不抛掷任何类型异常的函数声明如下:void fun() throw();

** Author:慕灵阁-wupke
** Time:2022-1-10
** Versions :11-1.cpp
** 
*
***************************************************/

#include<iostream>

using namespace std;

int divide(int x, int y){
    if (y==0)
        throw x;  // 抛出异常时的提示值
    return x/y; // 否则,没有异常,返回正常值
}
int main(){
    try
    {
        cout<<" 5/2  = " << divide(5,2) <<  endl; 
        cout<<" 6/0  = " << divide(6,0) <<  endl;    
        cout<<" 7/3  = " << divide(7,3) <<  endl;     
    }
    catch(int e)   // 注意异常捕捉的形式
    {
        cout << e << " is divided by zero !!!" << endl;
    }
    cout << " That is ook. " << endl;
 
    system("pause");
    return  0;
}


  • 示例2:
/*************************************************
**
**Description:  示例:带析构语义的类的C++异常处理机制
异常 抛出以后,未来得及析构的对象依然会被析构

** Author:慕灵阁-wupke
** Time:2022-1-10
** Versions :11-2.cpp
** 
*
***************************************************/
#include <iostream>
#include <string>

using namespace std;

class MyException {  //定义类
public:
    MyException(const string &message) : message(message) {} 
    ~MyException() {}  // 析构函数
    const string &getMessage() const { return message; }
private:
    string message;
};

class Demo {
public:
    Demo() { cout << "Constructor of Demo" << endl; }  // 构造函数
    ~Demo() { cout << "Destructor of Demo" << endl; }  // 析构函数
};

void func() throw (MyException) {
    Demo d;
    cout << "Throw MyException in func()" << endl;
    throw MyException("exception thrown by func()");
}

int main() {
    cout << "In main function" << endl;
    try {
        func();
    } catch (MyException& e) {
        cout << "Caught an exception: " << e.getMessage() << endl;
    } 
    cout << "Resume the execution of main()" << endl;

    
    return 0;
}

/*
运行结果:
In main function
Constructor of Demo
Throw MyException in func()
Destructor of Demo       // 可见,异常 抛出以后,未来得及析构的对象依然会被析构
Caught an exception: exception thrown by func()
Resume the execution of main()
*/

  • 示例3:
/*************************************************
**
**Description: 三角形面积计算

** Author:慕灵阁-wupke
** Time:2022-1-10
** Versions :11-3.cpp
** 
*
***************************************************/
#include <iostream>
#include <cmath>
#include <stdexcept>
using namespace std;

//给出三角形三边长,计算三角形面积
double area(double a, double b, double c) {
	//判断三角形边长是否为正
	if (a <= 0 || b <= 0 || c <= 0)
		throw invalid_argument("the side length should be positive");  
	//判断三边长是否满足三角不等式
	if (a + b <= c || b + c <= a || c + a <= b)
		throw invalid_argument("the side length should fit the triangle inequality");
	//由Heron公式计算三角形面积
	double s = (a + b + c) / 2;
	return sqrt(s * (s - a) * (s - b) * (s - c));
}

int main() {
	double a, b, c;	//三角形三边长
	cout << "Please input the side lengths of a triangle: ";
	cin >> a >> b >> c;

	try {
		double s = area(a, b, c);	//尝试计算三角形面积
		cout << "Area: " << s << endl;
	} catch (exception &e) {  //  若存在,捕获异常
		cout << "Error: " << e.what() << endl;
	}

    system("pause");
	return 0;
}

  • 示例4:
/*************************************************
**
**Description: 

声明一个异常类CException,有成员函数Reason0,
用来显示异常的类型,在子函数中触发异常,在主程序中处理异常,观察程序的执行流程。

** Author:慕灵阁-wupke
** Time:2022-1-10
** Versions :11-4.cpp
** 
*
***************************************************/
#include <iostream>

using namespace std;

class CException
{
public:
	CException() {}
    virtual ~CException() {}
	void Reason() {cout << "CException" << endl;}  // 在CException类的成员函数Reason)中用cout显示异常的类型
};

void fn1()
{
	throw CException();  // 在函数fn1()中用throw语句触发异常,即throw  CException();
}


int main()
{
	try {
		fn1();
	} catch (CException& ce) { //在catch模块中捕获异常,捕获的就是CException类的异常:Ecatch(CException&ce);
		ce.Reason();  
    }

    system("pause");
	return 0;
}

//  在本例中捕获之后的处理是查看异常的原因:ce.Reason();

  • 示例5:
/*************************************************
**
**Description: 综合实例:个人银行账户程序
    改进: 处理用户不符合要求的输入: 错误的日期查询、额度超出等等
         在检测到错误的地方将异常抛出。由主函数对这些异常进行统一处理
    其中:
·在构造或输入一个Date对象时如发生了错误
·直接使用标准程序库中的runtime_eror构造异常并抛出
·#include<stdexcept>
·用于使用标准程序库中的runtime_error构造异常并抛出


·在账户类中如发生了错误,由于希望异常信息能够标识是哪个账户发生了错误,因此:
·本程序中创建了一个类AccountException,
·该类从runtime_error派生,
·该类中保存了一个Account型常指针,指向发生错误的账户,
·这样在主函数中,输出错误信息的同时也可以将账号输出。

程序分为6个 文件:

Data.h  日期类的头文件 
Accumulator.h  按日将数值累加的Accumulator类 的头文件
Account.h 各个账户类定义的头文件
Data.cpp  日期类的实现文件
Account.cpp各个账户类实现的文件
Mian.cpp 主函数所在文件

** Author:慕灵阁-wupke
** Time:2022-1-10
** Versions :11-5.cpp
** 
*
***************************************************/

//date.h
#ifndef __DATE_H__
#define __DATE_H__
#include <iostream>

class Date {	//日期类
private:
	int year;		//年
	int month;		//月
	int day;		//日
	int totalDays;	//该日期是从公元元年1月1日开始的第几天

public:
	Date(int year = 1, int month = 1, int day = 1);	//用年、月、日构造日期
	int getYear() const { return year; }
	int getMonth() const { return month; }
	int getDay() const { return day; }
	int getMaxDay() const;		//获得当月有多少天
	bool isLeapYear() const {	//判断当年是否为闰年
		return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
	}
	//计算两个日期之间差多少天	
	int operator - (const Date& date) const {
		return totalDays - date.totalDays;
	}
	//判断两个日期的前后顺序
	bool operator < (const Date& date) const {
		return totalDays < date.totalDays;
	}
};

std::istream & operator >> (std::istream &in, Date &date);
std::ostream & operator << (std::ostream &out, const Date &date);
#endif //__DATE_H__
//date.h
#ifndef __DATE_H__
#define __DATE_H__
#include <iostream>

class Date {	//日期类
private:
	int year;		//年
	int month;		//月
	int day;		//日
	int totalDays;	//该日期是从公元元年1月1日开始的第几天

public:
	Date(int year = 1, int month = 1, int day = 1);	//用年、月、日构造日期
	int getYear() const { return year; }
	int getMonth() const { return month; }
	int getDay() const { return day; }
	int getMaxDay() const;		//获得当月有多少天
	bool isLeapYear() const {	//判断当年是否为闰年
		return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
	}
	//计算两个日期之间差多少天	
	int operator - (const Date& date) const {
		return totalDays - date.totalDays;
	}
	//判断两个日期的前后顺序
	bool operator < (const Date& date) const {
		return totalDays < date.totalDays;
	}
};

std::istream & operator >> (std::istream &in, Date &date);
std::ostream & operator << (std::ostream &out, const Date &date);
#endif //__DATE_H__





//date.cpp
#include "date.h"
#include <iostream>
#include <stdexcept>
using namespace std;

namespace {	//namespace使下面的定义只在当前文件中有效
	//存储平年中某个月1日之前有多少天,为便于getMaxDay函数的实现,该数组多出一项
	const int DAYS_BEFORE_MONTH[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
}

Date::Date(int year, int month, int day) : year(year), month(month), day(day) {
	if (day <= 0 || day > getMaxDay())
		throw runtime_error("Invalid date");
	int years = year - 1;
	totalDays = years * 365 + years / 4 - years / 100 + years / 400
		+ DAYS_BEFORE_MONTH[month - 1] + day;
	if (isLeapYear() && month > 2) totalDays++;
}

int Date::getMaxDay() const {
	if (isLeapYear() && month == 2)
		return 29;
	else
		return DAYS_BEFORE_MONTH[month]- DAYS_BEFORE_MONTH[month - 1];
}

istream & operator >> (istream &in, Date &date) {
	int year, month, day;
	char c1, c2;
	in >> year >> c1 >> month >> c2 >> day;
	if (c1 != '-' || c2 != '-')
		throw runtime_error("Bad time format");
	date = Date(year, month, day);
	return in;
}

ostream & operator << (ostream &out, const Date &date) {
	out << date.getYear() << "-" << date.getMonth() << "-" << date.getDay();
	return out;
}






//accumulator.h
#ifndef __ACCUMULATOR_H__
#define __ACCUMULATOR_H__
#include "date.h"

class Accumulator {	//将某个数值按日累加
private:
	Date lastDate;	//上次变更数值的时期
	double value;	//数值的当前值
	double sum;		//数值按日累加之和
public:
	//构造函数,date为开始累加的日期,value为初始值
	Accumulator(const Date &date, double value)
		: lastDate(date), value(value), sum(0) { }

	//获得到日期date的累加结果
	double getSum(const Date &date) const {
		return sum + value * (date - lastDate);
	}

	//在date将数值变更为value
	void change(const Date &date, double value) {
		sum = getSum(date);
		lastDate = date;
		this->value = value;
	}

	//初始化,将日期变为date,数值变为value,累加器清零
	void reset(const Date &date, double value) {
		lastDate = date;
		this->value = value;
		sum = 0;
	}
};

#endif //__ACCUMULATOR_H__





//account.h
#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__
#include "date.h"
#include "accumulator.h"
#include <string>
#include <map>
#include <istream>
#include <stdexcept>

class Account;	//前置声明

class AccountRecord {	//账目记录
private:
	Date date;				//日期
	const Account *account;	//账户
	double amount;			//金额
	double balance;			//余额
	std::string desc;		//描述
public:
	//构造函数
	AccountRecord(const Date &date, const Account *account, double amount, double balance, const std::string& desc);
	void show() const;	//输出当前记录
};

//定义用来存储账目记录的多重映射类型
typedef std::multimap<Date, AccountRecord> RecordMap;

class Account { //账户类
private:
	std::string id;	//帐号
	double balance;	//余额
	static double total; //所有账户的总金额
	static RecordMap recordMap;	//账目记录
protected:
	//供派生类调用的构造函数,id为账户
	Account(const Date &date, const std::string &id);
	//记录一笔帐,date为日期,amount为金额,desc为说明
	void record(const Date &date, double amount, const std::string &desc);
	//报告错误信息
	void error(const std::string &msg) const;
public:
	const std::string &getId() const { return id; }
	double getBalance() const { return balance; }
	static double getTotal() { return total; }
	//存入现金,date为日期,amount为金额,desc为款项说明
	virtual void deposit(const Date &date, double amount, const std::string &desc) = 0;
	//取出现金,date为日期,amount为金额,desc为款项说明
	virtual void withdraw(const Date &date, double amount, const std::string &desc) = 0;
	//结算(计算利息、年费等),每月结算一次,date为结算日期
	virtual void settle(const Date &date) = 0;
	//显示账户信息
	virtual void show(std::ostream &out) const;
	//查询指定时间内
	static void query(const Date& begin, const Date& end);
};

inline std::ostream & operator << (std::ostream &out, const Account &account) {
	account.show(out);
	return out;
}

class SavingsAccount : public Account { //储蓄账户类
private:
	Accumulator acc;	//辅助计算利息的累加器
	double rate;		//存款的年利率
public:
	//构造函数
	SavingsAccount(const Date &date, const std::string &id, double rate);
	double getRate() const { return rate; }
	virtual void deposit(const Date &date, double amount, const std::string &desc);
	virtual void withdraw(const Date &date, double amount, const std::string &desc);
	virtual void settle(const Date &date);
};

class CreditAccount : public Account { //信用账户类
private:
	Accumulator acc;	//辅助计算利息的累加器
	double credit;		//信用额度
	double rate;		//欠款的日利率
	double fee;			//信用卡年费

	double getDebt() const {	//获得欠款额
		double balance = getBalance();
		return (balance < 0 ? balance : 0);
	}
public:
	//构造函数
	CreditAccount(const Date &date, const std::string &id, double credit, double rate, double fee);
	double getCredit() const { return credit; }
	double getRate() const { return rate; }
	double getFee() const { return fee; }
	double getAvailableCredit() const {	//获得可用信用
		if (getBalance() < 0) 
			return credit + getBalance();
		else
			return credit;
	}
	virtual void deposit(const Date &date, double amount, const std::string &desc);
	virtual void withdraw(const Date &date, double amount, const std::string &desc);
	virtual void settle(const Date &date);
	virtual void show(std::ostream &out) const;
};

class AccountException : public std::runtime_error {
private:
	const Account *account;
public:
	AccountException(const Account *account, const std::string &msg)
		: runtime_error(msg), account(account) { }
	const Account *getAccount() const { return account; }
};
#endif //__ACCOUNT_H__






//account.cpp
#include "account.h"
#include <cmath>
#include <iostream>
#include <utility>
using namespace std;
using namespace std::rel_ops;

//AccountRecord类的实现
AccountRecord::AccountRecord(const Date &date, const Account *account, double amount, double balance, const std::string& desc)
	: date(date), account(account), amount(amount), balance(balance), desc(desc) { }

void AccountRecord::show() const {
	cout << date << "\t#" << account->getId() << "\t" << amount << "\t" << balance << "\t" << desc << endl;
}

//Account类的实现
double Account::total = 0;
RecordMap Account::recordMap;
Account::Account(const Date &date, const string &id)
	: id(id), balance(0) {
	cout << date << "\t#" << id << " created" << endl;
}

void Account::record(const Date &date, double amount, const string &desc) {
	amount = floor(amount * 100 + 0.5) / 100;	//保留小数点后两位
	balance += amount;
	total += amount;
	AccountRecord record(date, this, amount, balance, desc);
	recordMap.insert(make_pair(date, record));
	record.show();
}

void Account::show(ostream &out) const {
	out << id << "\tBalance: " << balance;
}

void Account::error(const string &msg) const {
	throw AccountException(this, msg);
}

void Account::query(const Date& begin, const Date& end) {
	if (begin <= end) {
		RecordMap::iterator iter1 = recordMap.lower_bound(begin);
		RecordMap::iterator iter2 = recordMap.upper_bound(end);
		for (RecordMap::iterator iter = iter1; iter != iter2; ++iter)
			iter->second.show();
	}
}

//SavingsAccount类相关成员函数的实现
SavingsAccount::SavingsAccount(const Date &date, const string &id, double rate)
	: Account(date, id), rate(rate), acc(date, 0) { }

void SavingsAccount::deposit(const Date &date, double amount, const string &desc) {
	record(date, amount, desc);
	acc.change(date, getBalance());
}

void SavingsAccount::withdraw(const Date &date, double amount, const string &desc) {
	if (amount > getBalance()) {
		error("not enough money");
	} else {
		record(date, -amount, desc);
		acc.change(date, getBalance());
	}
}

void SavingsAccount::settle(const Date &date) {
	if (date.getMonth() == 1) {	//每年的一月计算一次利息
		double interest = acc.getSum(date) * rate
			/ (date - Date(date.getYear() - 1, 1, 1));
		if (interest != 0)
			record(date, interest, " interest");
		acc.reset(date, getBalance());
	}
}

//CreditAccount类相关成员函数的实现
CreditAccount::CreditAccount(const Date& date, const string& id, double credit, double rate, double fee)
	: Account(date, id), credit(credit), rate(rate), fee(fee), acc(date, 0) { }

void CreditAccount::deposit(const Date &date, double amount, const string &desc) {
	record(date, amount, desc);
	acc.change(date, getDebt());
}

void CreditAccount::withdraw(const Date &date, double amount, const string &desc) {
	if (amount - getBalance() > credit) {
		error("not enough credit");
	} else {
		record(date, -amount, desc);
		acc.change(date, getDebt());
	}
}

void CreditAccount::settle(const Date &date) {
	double interest = acc.getSum(date) * rate;
	if (interest != 0)
		record(date, interest, " interest");
	if (date.getMonth() == 1)
		record(date, -fee, " annual fee");
	acc.reset(date, getDebt());
}

void CreditAccount::show(ostream &out) const {
	Account::show(out);
	out << "\tAvailable credit:" << getAvailableCredit();
}






//Main.cpp
#include "account.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;

struct deleter {
	template <class T> void operator () (T* p) { delete p; }
};

class Controller {	//控制器,用来储存账户列表和处理命令
private:
	Date date;					//当前日期
	vector<Account *> accounts;	//账户列表
	bool end;					//用户是否输入了退出命令

public:
	Controller(const Date &date) : date(date), end(false) { }
	~Controller();
	const Date &getDate() const { return date; }
	bool isEnd() const { return end; }
	//执行一条命名,返回该命令是否改变了当前状态(即是否需要保存该命令)
	bool runCommand(const string &cmdLine);
};
Controller::~Controller() {
	for_each(accounts.begin(), accounts.end(), deleter());
}
bool Controller::runCommand(const string &cmdLine) {
	istringstream str(cmdLine);
	char cmd, type;
	int index, day;
	double amount, credit, rate, fee;
	string id, desc;
	Account* account;
	Date date1, date2;

	str >> cmd;
	switch (cmd) {
	case 'a':	//增加账户
		str >> type >> id;
		if (type == 's') {
			str >> rate;
			account = new SavingsAccount(date, id, rate);
		} else {
			str >> credit >> rate >> fee;
			account = new CreditAccount(date, id, credit, rate, fee);
		}
		accounts.push_back(account);
		return true;
	case 'd':	//存入现金
		str >> index >> amount;
		getline(str, desc);
		accounts[index]->deposit(date, amount, desc);
		return true;
	case 'w':	//取出现金
		str >> index >> amount;
		getline(str, desc);
		accounts[index]->withdraw(date, amount, desc);
		return true;
	case 's':	//查询各账户信息
		for (size_t i = 0; i < accounts.size(); i++)
			cout << "[" << i << "] " << *accounts[i] << endl;
		return false;
	case 'c':	//改变日期
		str >> day;
		if (day < date.getDay())
			cout << "You cannot specify a previous day";
		else if (day > date.getMaxDay())
			cout << "Invalid day";
		else
			date = Date(date.getYear(), date.getMonth(), day);
		return true;
	case 'n':	//进入下个月
		if (date.getMonth() == 12)
			date = Date(date.getYear() + 1, 1, 1);
		else
			date = Date(date.getYear(), date.getMonth() + 1, 1);
		for (vector<Account*>::iterator iter = accounts.begin(); iter != accounts.end(); ++iter)
			(*iter)->settle(date);
		return true;
	case 'q':	//查询一段时间内的账目
		str >> date1 >> date2;
		Account::query(date1, date2);
		return false;
	case 'e':	//退出
		end = true;
		return false;
	}
	cout << "Inavlid command: " << cmdLine << endl;
	return false;
}

int main() {
	Date date(2008, 11, 1);	//起始日期
	Controller controller(date);
	string cmdLine;
	const char *FILE_NAME = "commands.txt";

	ifstream fileIn(FILE_NAME);	//以读模式打开文件
	if (fileIn) {	//如果正常打开,就执行文件中的每一条命令
		while (getline(fileIn, cmdLine)) {
			try {
				controller.runCommand(cmdLine);
			} catch (exception &e) {
				cout << "Bad line in " << FILE_NAME << ": " << cmdLine << endl;
				cout << "Error: " << e.what() << endl;
				return 1;
			}
		}
		fileIn.close();	//关闭文件
	}
	
	ofstream fileOut(FILE_NAME, ios_base::app);	//以追加模式
	cout << "(a)add account (d)deposit (w)withdraw (s)show (c)change day (n)next month (q)query (e)exit" << endl;
	while (!controller.isEnd()) {	//从标准输入读入命令并执行,直到退出
		cout << controller.getDate() << "\tTotal: " << Account::getTotal() << "\tcommand> ";
		string cmdLine;
		getline(cin, cmdLine);
		try {
			if (controller.runCommand(cmdLine))
				fileOut << cmdLine << endl;	//将命令写入文件
		} catch (AccountException &e) {
			cout << "Error(#" << e.getAccount()->getId() << "): " << e.what() << endl;
		} catch (exception &e) {
			cout << "Error: " << e.what() << endl;
		}
	}
	return 0;
}



  • 示例6:



  • 示例7:



  • 示例8:



  • 示例9:



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值