异常

异常

知道c++异常是怎么抛出的,我们怎么接受处理,及其过程

一、异常

1、什么是异常

1.异常是程序在执行期间产生的问题。c++的异常指的是程序在运行的时候所发生的一些特殊的情况。比如除法运算,除以0的操作

注意:我们平时看到的错误是语法错误

二、c++异常

1、c++异常的三个关键字

1.throw:用throw抛出异常

2.catch:用catch接受异常

3.try:在try中执行写有抛出异常的代码

2、示例

try
{
    throw "我是一个异常";
    cout<<"我是异常的下一句话"<<endl;
}
catch(const char* p)
{
    cout<<"出了异常"<<endl;
    cout<<p<<endl;
}

#include<iostream>
#include<windows.h>
using namespace std;
int fun(int a, int b)
{
	if (b == 0)
		throw "除数不能为0";
	return a / b;
}
//抛出的异常,和接收异常的地方类型要严格匹配,对于基本数据类型之间不会自动转换了
int main()
{
	try
	{
		//有抛出异常的代码
		fun(2, 0);
	}
	catch (const char* p)//将除数不能为0赋值给了p这个指针
	{
		//接收异常之后要做的事
		MessageBox(0, p, 0, 0);
	}
	system("pause");
	return 0;

}

注意:对于我们抛出的一个异常,我们必须接收,如果不接收就会报错,异常也可以嵌套,那么就会出现里层抛出一个异常,但是并没有在里层的catch块接收,那么外层如果有可以接收的,就会在外层接收

//有点像套娃
#include<iostream>
#include<windows.h>
using namespace std;
int fun(int a, int b)
{
	if (b == 0)
		throw "where";
	return a / b;
}
//抛出的异常,和接收异常的地方,类型要严格匹配
void test()
{
	try
	{
		//有抛出异常的代码
		fun(2, 0);
	}
	catch (const char* p)//将除数不能为0赋值给了p这个指针
	{
		cout << p << endl;
		throw 666.666;
		//接收异常之后要做的事
		//MessageBox(0, p, 0, 0);
	}
}
void test1()
{
	try
	{
		test();
	}
	catch (double a)
	{
		cout << a << endl;
		//cout << "我接住了异常1" << endl;
		throw "我不接这个锅";
	}
	
}
int main()
{
	try
	{
		test1();
	}
	catch (const char* p)
	{
		cout << p << endl;
	}
    
    catch(...)//可以接收任何异常(基本数据类型,但是像系统的异常接收不了)
    {
        cout<<"我接住了异常"<<endl;
    }
	system("pause");
	return 0;

}

3、异常的生命周期

1.如果说抛出的异常是一个变量,那么这个变量的存活周期会从throw抛出异常开始直到接收这个异常,在这个过程中,这个变量都会存活

4、栈解旋(了解)---一种现象

1.从try开始,到throw抛出异常之前,所有栈上的对象会被释放,这个过程被称之为:栈解旋

#include<iostream>
#include<windows.h>
using namespace std;
class person
{
public:
	person()
	{
		cout << "构造" << endl;
	}
	~person()
	{
		cout << "析构" << endl;
	}
};
int fun(int a, int b)
{
	if (b == 0)
	{
		person p1;
		person p2;
		person p3;
		throw p3;
	}
	return a / b;
}
int main()
{
	try
	{
		fun(1, 0);
	}
	catch(person& p)
	{
		cout << "接收到了异常" << endl;
	}
    /*
    构造
	构造
	构造
	析构
	析构
	析构
	接收到了异常
	析构
	*/
	system("pause");
	return 0;

}

5、自定义异常

下面是c++的一系列标准的异常,定义中我们是可以直接使用这些类的

异常

异常描述

系统异常类的使用

#include<iostream>
#include<exception>
#include<string>
using namespace std;
//自己写的异常类
class myexception :public exception
{
	string str;
public:
	myexception(string str)
	{
		this->str = str;
	}
	const char* what()const
	{
		return str.c_str();
	}
};

//异常多态的使用,还是父类指针指向子类对象,通过父类指针调用虚函数成员
int main()
{
	//系统的异常类都是带参构造
	//out_of_range oor("我是一个字符串");
	myexception me("我也是一个字符串");
	try
	{
		//throw oor;
		throw me;
	}
	catch (exception&e)
	{
		cout << e.what() << endl;
	}


	system("pause");
	return 0;

}

三、c++11

1、初始化列表的方式

//旧写法
int a;
int b(2.1);//将2赋值给b,但是小数点后的被省掉了 
//新写法
int m{4};
int n={(int)3.14};//新的写法不允许有精度的损失

2、空指针

int* p=NULL;//旧写法
int* p1=nullptr;//新写法

3、自动类型

int a=1;//旧写法
auto b=2;//新写法,根据值去自动匹配b的类型,必须初始化
auto i={1,2,3};

//typeid(变量名).name()  返回变量的类型
cout<<typeid(b),name()<<endl;//int


//用来遍历数组,遍历有效内容,只是遍历
int arr[]={1,2,3,5,6,8,6,5};
for(auto i:arr)
{
    cout<<i<<" ";
}

4、decltype()

int a=1;
decltype(a)b;//理解为根据a的类型定义了一个和a类型一致的b变量
decltype((a))m=a;//再加一个圆括号,给a定义了一个别名m

5、新的for规则

string str="awdwdwf";
//遍历这个str
//旧方法
for(int i=0;i<str.size();i++)
{
    cout<<str[i]<<endl;
}
//新方法
for(auto i:str)//这里其实使用的是迭代器输出
{
    cout<<i<<endl;
}
//这个方法,只能用来遍历数组,容器,i所代表的是里面存的元素,如果是个指针,那么是不能这样遍历的

6、给类型取别名

typedef int hp;//旧写法
using hp=int;//新写法

typedef void (*pfun)();//旧写法
using pfun=void(*)();//新写法

7、default在类中的写法

class A
{
    public:
    A();
}
A::A()=default;//默认调用默认构造

8、final禁止虚函数发生重写

class A
{
    public:
    virtual void fun()final{}
    //意味着这个虚函数,不能被子类重写,也就是说子类必须用父类的虚函数,所以父类的这个虚函数必须实现其功能
}
原文地址:https://www.cnblogs.com/Kissfly123/p/14488913.html