1. 基本语法
通过异常可以使原本会发生宕机的异常被特殊处理。程序给出提示,但程序不崩溃。
- 发生异常之后,是跨函数的
- 接收异常之后,可以不处理,再抛出
- catch异常时,按照类型进行catch
- 异常捕捉严格按照类型匹配
#include <iostream>
using namespace std;
//1 发生异常之后,是跨函数的
//2 接收异常之后,可以不处理,再抛出
//3 catch异常时,按照类型进行catch
//4 异常捕捉严格按照类型匹配
//异常的 栈解旋 就是在抛出异常时,调用相应的析构函数。
void divide(int x, int y)
{
if (y == 0)
{
throw x;//抛出int类型异常
}
cout << "divide result: " << x / y << endl;
}
//发生异常之后,是跨函数的
void myDivide(int x, int y)
{
try
{
divide(x, y);
}
catch (...)
{
cout << "我接收了divide的异常,不处理往上抛" << endl;
throw;
}
}
int main()
{
try
{
divide(10, 2);
//divide(100, 0);
myDivide(20, 0);
}
catch (const int e)
{
cout << e << " is divided by 0!" << endl;
}
catch (...)
{
cout << "其他未知类型异常" << endl;
}
return 0;
}
2. 栈解旋和异常接口声明
#include <iostream>
using namespace std;
class Test3
{
public:
Test3(int a = 0, int b = 0)
{
this->a = a;
this->b = b;
cout << "构造函数" << endl;
}
~Test3()
{
cout << "析构函数" << endl;
}
private:
int a;
int b;
};
//不写,抛出所有类型异常
void myDivide()
{
Test3 t1(1, 2), t2(3, 4);
cout << "myDide即将发生异常" << endl;
throw 1;//抛出异常时,会析构t1,t2,这就是栈解旋,这样可以防止程序崩溃
}
//抛出已写类型的异常
void myDivide2() throw(int, char, char*)
{
Test3 t1(1, 2), t2(3, 4);
cout << "myDide2即将发生异常" << endl;
throw 1;
}
//不抛出任何类型的异常
void myDivide3() throw()
{
Test3 t1(1, 2), t2(3, 4);
cout << "myDide3即将发生异常" << endl;
throw 1;
}
int main()
{
try
{
//myDivide();//抛出异常时,程序结束
myDivide2();
//myDivide3();
}
catch (int a)
{
cout << "int 型异常" << endl;
}
return 0;
}
3. 异常的生命周期
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//使用异常的方式进行处理
void my_strcpy1(char *dst, char *from) {
if (dst == NULL) {
throw 1; //1 代表目的地址有问题
}
else if (from == NULL) {
throw 2; //2 代表源地址有问题
}
if (*from == 'a') {
throw 3; //代表copy过程出现问题
}
while (*from != '\0') {
*dst = *from;
dst++;
from++;
}
*dst = '\0';
}
void my_strcpy2(char* dst, char *from)
{
if (dst == NULL) {
throw "目的地址有问题"; //1 代表目的地址有问题
}
else if (from == NULL) {
throw "源地址有问题"; //2 代表源地址有问题
}
if (*from == 'a') {
throw "copy过程出现问题"; //代表copy过程出现问题
}
while (*from != '\0') {
*dst = *from;
dst++;
from++;
}
*dst = '\0';
}
//目的地址有问题的异常类型
class BadDstAddrType{};
class BadSrcAddrType{};
class BadProcessAddrType{
public:
BadProcessAddrType()
{
cout << "BadProcessAddrType().." << endl;
}
BadProcessAddrType(const BadProcessAddrType & obj)
{
cout << "BadProcessAddrType(const BadProcessAddrType &)..." << endl;
}
void print() {
cout << "copy过程出现了异常" << endl;
}
~BadProcessAddrType(){
cout << "~BadProcessAddrType()..." << endl;
}
};
void my_strcpy3(char *dst, char *from)
{
if (dst == NULL) {
throw BadDstAddrType(); //1 代表目的地址有问题
}
else if (from == NULL) {
throw BadSrcAddrType(); //2 代表源地址有问题
}
if (*from == 'a') {
//throw new BadProcessAddrType(); //在抛出这个BadProcessAddrType() 会创建一个匿名对象
throw BadProcessAddrType();
}
while (*from != '\0') {
*dst = *from;
dst++;
from++;
}
*dst = '\0';
}
int main(void)
{
char buf1[] = "a234567";
char buf2[128] = { 0 };
try {
my_strcpy3(buf2, buf1);
}
catch (int e)
{
cout << "捕获到异常代码e = " << e << endl;
}
catch (char *e)
{
cout << "捕获到char*类型异常e = " << e << endl;
}
//catch (BadProcessAddrType e) { //BadProcessAddrType e = 匿名对象temp //在捕获的时候,如果用一个元素捕获
//会发生拷贝构造,异常对象e和被抛出来的匿名对象不是一个对象
//会有深拷贝和浅拷贝的风险
// cout << "捕获到了BadProcessAddrType 异常类型e " << endl;
// e.print();
// }
catch (BadProcessAddrType *e) { //此时那个匿名对象已经被释放了,e是一个野指针
cout << "捕获到了BadProcessAddrType* 异常类型e" << endl;
delete e; //如果抛出的异常类型是new出来的,需要显示的delete掉
}
catch (BadProcessAddrType &e) { //1 普通元素类型的异常捕获,不能够跟 引用捕获同时存在。
cout << "捕获到了 BadProcessAddrType & 异常类型" << endl;
//编译器发现使用引用捕获的,那么不会立刻释放掉匿名对象, 而是在异常处理完之后,才把e释放。
//可以理解为 BadProcessAddrType &e = BadProcessAddrType()
}
catch(...)
{
cout << "捕获到未知异常" << endl;
}
}
#if 0
int my_strcpy(char *dst, char *from)
{
if (dst == NULL) {
return 1; //1 代表目的地址有问题
}
else if (from == NULL) {
return 2; //2 代表源地址有问题
}
if (*from == 'a') {
return 3; //代表copy过程出现问题
}
while (*from != '\0') {
*dst = *from;
dst++;
from++;
}
*dst = '\0';
return 0;
}
//传统的捕获错误方法
int main(void)
{
char buf1[] = "a234567";
char buf2[128] = { 0};
int ret = 0;
ret = my_strcpy(buf2, buf1);
if (ret != 0) {
switch (ret)
{
case 1:
cout << "目的地址有问题" << endl;
break;
case 2:
cout << "原地址有问题" << endl;
break;
case 3:
cout << "拷贝过程有问题" << endl;
break;
default:
break;
}
}
else {
cout << "buf2 = " << buf2 << endl;
}
return 0;
}
#endif
4. 异常的层次结构
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class eSize
{
public:
eSize(int len)
{
this->len = len;
}
virtual void printErr() {
cout << "eSize error: len = " << len << endl;
}
protected:
int len;
};
class eNagtive :public eSize
{
public:
eNagtive(int len): eSize(len) {
}
virtual void printErr()
{
cout << "eNagtive error: len = " << len << endl;
}
};
class eZero :public eSize
{
public:
eZero(int len) :eSize(len) {
}
virtual void printErr()
{
cout << "eZero error: len = " << len << endl;
}
};
class eTooBig :public eSize
{
public:
eTooBig(int len) :eSize(len) {
}
virtual void printErr()
{
cout << "eTooBig error: len = " << len << endl;
}
};
class eTooSmall :public eSize
{
public:
eTooSmall(int len) :eSize(len) {
}
virtual void printErr()
{
cout << "eTooSmall error: len = " << len << endl;
}
};
class MyArray
{
public:
MyArray(int len)
{
if (len < 0) {
throw eNagtive(len);
}
else if (len == 0) {
throw eZero(len);
}
else if (len > 1000) {
throw eTooBig(len);
}
else if (len < 10) {
throw eTooSmall(len);
}
this->len = len;
this->space = new int[len];
}
int & operator[](int index)
{
return this->space[index];
}
int getLen()
{
return this->len;
}
~MyArray() {
if (this->space != NULL) {
delete[] this->space;
this->space = NULL;
this->len = 0;
}
}
private:
int len;//元素的个数
int *space;
};
int main(void)
{
try {
MyArray array(3);
for (int i = 0; i < array.getLen(); i++) {
array[i] = i + 1;
}
for (int i = 0; i < array.getLen(); i++) {
cout << array[i] << endl;
}
}
catch (eSize &e) //eSize &e = eNagtive(len);
{
cout << "捕获到异常" << endl;
e.printErr();//发生多态
}
#if 0
catch (eNagtive &e)
{
cout << "捕获到eNagive 异常" << endl;
e.printErr();
}
catch (eZero &e) {
cout << "捕获到eZero 异常" << endl;
e.printErr();
}
catch (eTooBig &e) {
cout << "捕获到eTooBig 异常" << endl;
e.printErr();
}
catch (eTooSmall &e) {
cout << "捕获到eTooSmall 异常" << endl;
e.printErr();
}
catch (...)
{
cout << "捕获到未知异常" << endl;
}
#endif
return 0;
}
5. 标准异常库
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
//自定义的MyException 也加入标准的异常库
class MyException :public exception
{
public:
MyException(char *str) {
this->m_s = str;
}
virtual const char *what() const{
cout << "MyException 的异常" << endl;
return this->m_s;
}
private:
char *m_s;
};
class Teacher
{
public:
Teacher(string name, int id)
{
this->name = name;
if (id > 100) {
string str = "id 超出范围";
throw out_of_range(str);
}
this->id = id;
}
private:
int id;
string name;
};
int main(void)
{
try
{
Teacher t1("zhangsan", 10001);
}
catch (exception &e)
{
cout << e.what() << endl;
}
try {
throw MyException("aaaa");
}
catch (exception &e){
cout << e.what() << endl;
}
return 0;
}