异常处理

为什么需要异常机制?
类的设计和使用是分离的,设计者也可能知道一些异常情况,当出现这样的异常情况,需要停止当前执行,并以一种机制来告知使用者。类的使用者能根据所使用的类中可能出现的所有异常情况来决定如何处理各种情况!

异常处理机制包括:抛出异常和捕获异常。
抛出异常:类的设计内进行抛出,一旦抛出异常,程序的正常执行将被停止。而类的设计者有权处理这种异常,为此通常使用类的函数中进行捕获,这称为捕获异常,当捕获该异常后,可进行一些处理,此时程序将从捕获到异常的程序开始接着执行下去。可以看出,程序运行的轨迹是正常—中断–异常处理—正常。

抛出异常(throw exception):
throw 对象,对象可以是已实现的异常类对象或是自定义异常类对象。
捕获异常(catch exception):
catch(类型或是对象){对异常的处理} 使用对象呢,就可以利用异常类的方法做些事来,若只是利用异常类,那就无法调用异常类的方法,根据需要选择只写类型还是类型对象!
注意catch子句是有顺序的,这主要针对异常类存在继承关系,一旦匹配到一个catch子句,之后的都不会被检测和进入。
catch的代码主体内,是希望我们对异常情况做一些处理,但是当前可能无法实现完整的操作,因此,我们可以重抛throw!throw子句只能出现在catch子句中!会将捕获的异常类型再次抛出。

try for exception :
catch子句要搭配try使用,表明try内所发生的异常由其后的catch子句处理。
函数调用是个很神奇的事,类中的一个函数很可能被另一个函数调用,但并不是调用到产生异常的函数都需要进行异常捕获的(可以不捕获异常,但得保证不捕获不影响程序的正确性和安全性)!不进行捕获,函数就返回到上一个调用端(这意味着什么?不进行捕获异常的函数,一旦真的发生了异常,函数体之后的部分都无法执行到了。可以说这是省事带来的恶果吗?哈哈哈,也并不是这样的,并每个函数都写try catch 也挺麻烦的, 因此我们要有选择的写try catch)。不断返回调用端,直到找到try 和catch子句,若能捕获异常,则进行异常处理(异常处理的地方,这是设计者决定的!决定异常是自己处理后留下异常记录呢(包括在哪里处理异常),自己处理了异常返回结果给用户程序,使得程序就像没事人似的正常执行?还是不处理异常交由用户处理呢?
看下面这个例子,这使得这个函数的调用者执行完全没被发生的异常所干扰。因为在函数的设计中,已经解决了异常。但是函数*()和check_integrate()被中断了,这个中断是必要的,否则就要出大问题了,越界访问!
异常为我们带来了什么?原先我们只能只能使用布尔型变量表示函数执行的成功与否,但现在我们不需要再每个调用可能产生异常的函数中都去做条件检测,而是利用异常机制的函数调用链端的返回匹配catch子句,保证了调用产生了异常的函数在真的发生异常后也能判断该执行什么(有合适try子句的),不该执行什么(没有try子句或是没有匹配到catch子句的)。这么看来没有异常机制也是可以的?但这样我们的函数统一设计为布尔型,都加上条件判断,这绝对不是我们写程序所希望遇到的情况。
异常机制保证了函数不能正确执行时就返回调用端,一直返回(不处理异常),直到遇到能处理异常的情况后,处理过后在此调用节点上正常执行。
在这里插入图片描述在这里插入图片描述上面这个函数就是希望调用端、函数本身通过不处理异常(重抛)来保证不产生危险行为!而下面这个例子则是在产生异常的后面立即加上异常处理,这样当异常真的发生了也不会干扰到调用端函数的执行。可以对比一下,异常处理时机选择的准则!
在这里插入图片描述在这里插入图片描述

函数内定义的局部变量无论是正常执行下还是异常中断下,都会调用自身的析构函数释放空间,删除所占用的函数栈空间。

throw 异常类对象,这说明什么?C++肯定是为我们提供了一些预定义的异常类型可以直接使用它们,同时可以使用自定义的异常类类型,这里可以继承C++实现的抽象基类exception,其中包含虚函数what()需要自行实现,进而实现自己的异常类型。为什么要继承异常基类exception呢?catch子句中使用exception类型的引用就能捕获到其所有的派生类对象,在异常处理方法中的函数调用也可以实现多态性。使用异常基类需要包含头文件exception。
在这里插入图片描述在这里插入图片描述
exception抽象基类的一个具体派生类bad_alloc,当我们使用new分配内存空间失败时,将抛出bad_alloc类对象。
在这里插入图片描述
补充一下关于输入输出的语法:
头文件sstream中两个特殊的类:
ostringstream:将字符串、数值以字符串的方式写入到内存的ostringstream对象中。
在这里插入图片描述在这里插入图片描述之前实现过例子,为其加入异常处理机制。由于调用者并不关心这个异常,作为类的设计者,我们采取了自己消化异常!

#include<vector>
#include<iostream>
using namespace std;
class Triangular_iterator {
public:
	Triangular_iterator(int next):_ne(next){}
	bool operator==(const Triangular_iterator &) const;
	bool operator!=(const Triangular_iterator &) const;
	int operator*() ;
	Triangular_iterator & operator++();
	Triangular_iterator operator++(int);
private:
	int _ne;
	void is_legal();
};
class Triangular {
	friend class Triangular_iterator;
	friend class Iterator_overflow;
public:
	bool find_ele(int val);
	friend ostream & operator<<(ostream &os, Triangular & a);
	friend istream & operator >> (istream & is, Triangular &a);
	typedef Triangular_iterator iterator;
//	friend class Triangular_iterator;
	int get_len() { return _len; }
	int get_begin() { return _begin; }
	int get_next() { return _next; }
	iterator begin() {
		return iterator(_begin);
	}
	iterator end() {
		return iterator(_begin + _len);
	}
	void get_value(int &) const ;//根据next获取当前元素值
	bool get_pos(int pos, int &) const;
	static void gen(int n);//根据长度判断是否需要填充static 对象
	static bool is_ele(int value);
	static void gen_by_val(int value);
	Triangular(int l = 0, int b = 0);
	void display(ostream &os = std::cout) const;
	static void showall();
private:
	static vector<int> _eles;//所有对象都共享 每个对象根据数据成员得以区别数列长度  当数列不够长 改变这个数据成员 否则每个对象只是维护各自的标记
	int _begin;//透过这些数据成员使得每个对象时有所不同的  第几个元素开始
	int _len;//
	const static int max_l = 1024;
	mutable int _next;//从0开始索引值 初始化为数列的第一个元素 用于遍历 相当于索引
};

class Less_than {
public:
	Less_than(int v) { value = v; }
	void set_v(int v) { value = v; }
	int get_v() {
		return value;
	}
	bool operator()(int v) {
		return v < value;
	}
private:
	int value;
};
#include"triangular.h"
#include<algorithm>
#include<iostream>
#include<vector>


vector<int> Triangular::_eles;  //由于静态变量没有在类外再次声明 导致编译器出现无法加载vector!!!
void Triangular::get_value(int & result) const//根据next获取当前元素值
{
	result = _eles[_next++];
}
bool Triangular::get_pos(int pos, int &val) const//pos从0开始取值
{
	if (pos <= _begin + _len - 1)//begin从0开始取值
	{
		val = _eles[pos];
		return true;
	}
	return false;
}
void Triangular::gen(int index)// index指出了填充到哪里
{
	if (_eles.size() == 0)
	{
		_eles.push_back(1);
	}
	int i = _eles.size();
	for (; i <= index; i++)
	{
		_eles.push_back(i*(i + 1) / 2);
	}
}
bool Triangular::is_ele(int value)
{
	int cur = _eles.back();
	if (value > cur)
	{
		gen_by_val(value);
	}
	return std::find(_eles.begin(), _eles.end(), value) != _eles.end();
}
void Triangular::gen_by_val(int value)
{
	int s = _eles.size();
	if (s == 0)
	{
		_eles.push_back(1);
		s++;
	}
	while (_eles.back() < value)
	{
		_eles.push_back(s*(s + 1) / 2);
		s++;
	}
}

void Triangular::display(ostream &os) const
{
	for (int i = _begin; i < _begin + _len; i++)
	{
		os << _eles[i] << " ";
	}
	os << endl;
}
void Triangular::showall()
{
	for (auto x : _eles)
	{
		std::cout << x << " ";
	}
	std::cout << std::endl;
}

Triangular::Triangular(int l, int b) {
	_begin = (b <= 0 ? 0 : b);
	_len = (l <= 0 ? 0 : l);
	if (_begin + _len> _eles.size()) {//实际需要的个数和现在向量中的个数比较 若是现有的向量无法满足我们的要求则扩充
		gen(_begin + _len - 1);
	}
	_next = _begin;
	//gen(_len);
}
const  int Triangular:: max_l = 1024;


bool Triangular::find_ele(int val)
{
	
	iterator it = begin();
	try {
		while (it != end())
		{
			if (*it == val)
			{
				return true;
			}
			else
				it++;
		}
	}
	catch (Iterator_overflow &a) {
		a.what();
	}
	return false;//异常也罢,没找到也罢,返回的都是false。
}
#include"triangular.h"
#include<exception>


class Iterator_overflow :public std::exception {
public:
	const char *what() const {
		std::cout << "iterator overflow! index value is " << _index << " max size is " << Triangular::max_l << std::endl;
	}
	Iterator_overflow(int i) :exception() {
		_index = i;
	}
private:
	int _index;
};

//为什么一定要创建这样的一个类?难道使用Triangular类的next不可以吗?
//就是为了和模板容器类型达成统一,使用泛型算法!这就需要对索引值进行++、*操作,++好说,但是*不支持作用于在int类型的变量上,获取元素的操作不能得到统一
bool Triangular_iterator::operator==(const Triangular_iterator & a) const
{
	return _ne == a._ne;
}
bool Triangular_iterator::operator!=(const Triangular_iterator & a) const
{
	return !(*this == a);
}
int  Triangular_iterator::operator*()  //这里是有Triangular类中int类型的索引值很大的一个区别 能对int类型的变量用*吗???但是在这里通过定义一个类 就可以实现这种操作!这也是值的深思的地方
{
	is_legal();
	return Triangular::_eles[_ne];//成员是静态的,被类所持有,很特别的地方!还需要多多反思
}
Triangular_iterator & Triangular_iterator::operator++()
{
	_ne++;
	return *this;
}
Triangular_iterator Triangular_iterator:: operator++(int)
{
	Triangular_iterator temp = *this;
	_ne++;
	return temp;
}

void Triangular_iterator::is_legal()
{
	if (_ne > Triangular::max_l)
		throw Iterator_overflow(_ne);
	else if (_ne > Triangular::_eles.size()) {
		Triangular::gen(_ne);
	}
	//else if()
}

#include"triangular.h"
#include<iostream>
#include<algorithm>
int sum(Triangular & a);
int count_less_value(vector<int> & a, int v);
ostream & operator<<(ostream &os, Triangular & a);
istream & operator >> (istream & is, Triangular &a);
int main()
{
	Triangular::gen(10);
	cout << "input len and begin:";
	Triangular c;
	cin >> c;
	cout << c;
	Triangular b(6, 3);
	//b.display();
	std::cout << b;

	Triangular::showall();
	vector<int> test1 = { 1,2,55,3,5,6 };
	int num=count_less_value(test1, 10);
	cout << "less than 10 " << num << endl;
	Triangular a(5,0);
	Triangular_iterator it = a.begin();
	while (it != a.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	
	int s = sum(a);
	cout << s << endl;
//	int v;
	int m;
	cin >> m;
	if (Triangular::is_ele(m))
		cout << "yes" << endl;
	else
		cout << "no" << endl;
	/*if (a.get_pos(m, v))
		cout << v << endl;
	else
		cout << " out of range!" << endl;*/
	
	Triangular::showall();
	a.display();
	
	//Triangular::showall();
	//cout << a.get_len() << " " << a.get_begin() << endl;
	
	//b.display();

	std::cin.get();

	std::cin.get();
	return 0;
}

int sum(Triangular & a)
{
	int i = a.get_begin();
	int len = a.get_len();
	int sum = 0;
	int temp;
	for (; i < a.get_begin() + len; i++)
	{
		if (a.get_pos(i, temp))
			sum += temp;
	}
	return sum;
}

int count_less_value(vector<int> & a, int v)
{
	int count = 0;
	Less_than lt(v);
	vector<int>:: iterator it=a.begin();
	while ((it = std::find_if(it, a.end(), lt)) != a.end())
	{
		cout << *it << " ";
		it++;
		count++;
		
	}
	cout << endl;
	return count;
}
ostream & operator<<(ostream &os, Triangular & a)
{
	if (a._begin + a._len > Triangular::_eles.size())
		Triangular::gen(a._begin + a._len - 1);
	a.display();
	return os;
	
}
istream & operator >> (istream & is, Triangular &a)
{
	int beg;
	int length;
	is >> beg >> length;
	a._begin = beg;
	a._len = length;
	a._next = beg;
	if(beg+length>a._eles.size())
		Triangular::gen(a._begin + a._len - 1);
	return is;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值