c++异常机制

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>

#include <string>

#include <stdexcept>

using namespace std;

class Person

{

public:

Person()

{

a = 1;

cout << "Parent()..." << endl;

}

~Person()

{

cout << "~Parent()..." << endl;

}

private:

int a;

};

//异常基本语法

int divide(int x, int y)

{

//unwinding(栈解旋)

Person p1, p2;//当函数抛出异常时,这个函数里定义的所有变量都会被析构,这种行为成为unwinding(栈解旋)

if (y == 0)

{

throw y;//抛异常,抛出异常后,后面的代码就不再执行了

}

cout << "correct" << endl;

return x / y;

}

//最底层的函数抛出异常,会一级级向上抛出,如果上一级没有进行处理会抛到更上一层,直到处理,但如果抛到最顶层还没有被处理,则这个程序就会被终止

//因此c++异常机制是跨函数的,是必须处理的

void test1(int x, int y)

{

divide(x, y);

}

//异常接口声明

//表示这个函数只能抛出int, float, char三种类型异常,抛出其他异常报错

void func1() throw(int, char, float)

{

throw 3;

}

//这种写法为不能抛出任何异常

void func2() throw()

{

}

//这种写法为可以抛出任何异常

void func3()

{

}

class Teacher

{

public:

//异常可以抛出对象,因此可以在类中定义异常的打印函数

Teacher(const char * p)

{

int len;

len = strlen(p) + 1;

this->p = new char[len];

strcpy(this->p, p);//拷贝\0

cout << "调用了构造函数" << endl;

}

Teacher(const Teacher &t)

{

int len;

len = strlen(t.p) + 1;

this->p = new char[len];

strcpy(this->p, t.p);//拷贝\0

cout << "调用了拷贝构造函数" << endl;

}

Teacher &operator=(Teacher &t)

{

int len;

len = strlen(t.p) + 1;

this->p = new char[len];

strcpy(this->p, t.p);//拷贝\0

cout << "调用了赋值函数" << endl;

}

~Teacher()

{

delete[] p;

cout << "调用了析构函数" << endl;

}

void what()

{

cout << "发生异常" << endl;

}

private:

//string p;//使用string类型,是不需要考虑赋值函数和拷贝构造函数的,只有私有成员里有指针时,才需要考虑

char *p;

};

void temp1()

{

//这儿的流程是先调用构造函数,生成一个匿名对象(注意这个匿名对象其实与有名对象意义一样),然后调用拷贝构造函数再建一个匿名对象,把这个用拷贝构造函数声明的匿名对象传给catch函数,然后直接命名,不调用赋值函数

throw Teacher("111");//这儿抛出的是匿名对象,且这儿调用了拷贝构造函数

//throw new Teacher("111");传指针的话用这种方法传递,先在堆中创建一个对象,并返回指针,然后把指针扔出,这时catch用指针去接,执行完逻辑需要delete[],因为这个对象这堆空间,不会主动触发析构函数,需要delete去主动触发析构函数

}

//编写自己的异常类:

//1.最好要继承标准异常类

//下面两条,当你使用exception类的成员变量时,就不需要重写拷贝构造函数和析构函数,但如果子类自己定义一个成员变量时,就需要重写父类的析构函数和what()函数

//仍是下面两条,我认为看情况写与不写,不是一定要写的,有时也不一样要继承,直接定义一个类扔出就可以了

//2.当继承标准异常类时,应重写父类的what函数和虚析构函数

//3.考虑是否显示写出拷贝构造函数和赋值函数,防止发生错误

class MyOutOfRange :public exception

{

public:

MyOutOfRange(const char *error) :exception(error)

{

}

/*

MyOutOfRange(const MyOutOfRange &m)

{

int len = strlen(m.error) + 1;

this->error = new char[len];

strcpy(this->error, m.error);

}

*/

/*

~MyOutOfRange()

{

if (error != NULL)

{

delete[] error;

}

}

*/

/*

virtual char const* what() const//const是修饰在本函数的生命周期内,传入的对象不可更改

{

return error;

}

*/

private:

};

class Animal

{

public:

Animal()

{

age = 0;

}

void setAge(int age)

{

if (age < 0 || age>100)

{

throw out_of_range("年龄不是在0-100之间");

}

else

{

throw MyOutOfRange("年龄是在0-100之间");

}

}

private:

int age;

};

//继承在异常中的应用

class Base

{

public:

virtual void what() = 0;

virtual ~Base() {};

private:

};

class SourceNull :public Base

{

public:

virtual void what()

{

cout << "资源为空" << endl;

}

private:

};

void myCopy(char *q, const char *p)

{

if (p == NULL)

{

throw SourceNull();

}

while (*p != '\0')//一定需要这样写,不能写成*p != 0这种形式

{

*q = *p;

p++;

q++;

}

*q = '\0';

}

int main()

{

//试着去捕获异常,如果没有发生异常,则正常执行,如果发生异常,根据抛出的对象类型进行匹配,然后执行catch里的内容

try {

divide(10, 0);

//divide(10, 1);//不能这样写,一个事件对应一个try...catch,当上面事件的异常被捕捉时,后面的代码就不再执行了,直接执行catch匹配到的逻辑

}

catch (int y) {//根据抛出的异常进行匹配,我们throw抛出的是int类型,因此catch (int)捕获的应是int类型,也可以把抛出的变量接住,写法:catch (int y)

cout << "error" << endl;

}

try {

test1(10, 0);

}

catch (int y) {

cout << "error" << endl;

}

try {

func1();

//devide();//可以不用明确规定抛出的异常为什么类型,这种写法也是可行的

}

catch (char a) {

cout << "char" << endl;

}

catch (int a) {

cout << "int" << endl;

}

catch (float a) {

cout << "float" << endl;

}

//这种写法为捕获所有异常

catch (...) {

cout << "unknown" << endl;

}

try {

temp1();

}

catch (Teacher t) {

t.what();

//delete t;//当接收的是指针时

}

Animal a;

try {

a.setAge(50);

}

//我们扔出的就是out_of_range类型的对象

//因为标准库异常都是继承exception类的,因此可以直接用父类对象去接子类对象

//这儿其实有个问题,因为是父类对象去接子类对象的,因此不会发生多态,但下面调用e.what()看起来却是发生了多态,我想这个what()函数输出的字符串为父类里的字符串,并不是子类新定义的字符串,因此因为是直接对父类中变量直接赋值,所以当然赋值什么输出什么,通过追原码,这儿就是为父类中定义的对象赋值,且也是输出父类中的变量

catch (exception e) {

cout << e.what() << endl;

}

const char *p1 = "111";

char *p2 = NULL;

char q[64] = { 0 };

try {

myCopy(q, p1);

}

catch (SourceNull s)

{

s.what();

}

cout << q << endl;

return 0;

}

猜你喜欢

转载自blog.csdn.net/tulipless/article/details/81135099