C++学习笔记:异常的基本语法
2016-03-05 10:32
483 查看
1)若有异常 则通过throw 操作 创建一个异常对象 并抛出。
2)将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句。然后执行try块内的保护段
3)如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去
4)catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛出异常)
5)如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序
6)处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上扔
2.栈解旋
执行throw语句后,相当于 return ,但是不是,会调用析构函数 释放掉栈空间
3.异常的接口声明
1)为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常累成,例如:
void func() throw(A,B,C,D);//这个函数func()能够且只能抛出类型A B C D及其子类型的异常
2)如果在函数声明中没有包含异常接口声明,则该函数可以抛出任何类型的异常,例如:
void func();
3)一个不抛出任何类型异常的函数可以声明为:
void func() throw();
4)如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpercted函数会被调用,该函数默认行为调用terminate函数终止程序。
4.异常变量的声明周期
方式二:
方式三:
2)将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句。然后执行try块内的保护段
3)如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去
4)catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛出异常)
5)如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序
6)处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上扔
// 异常的基本语法.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> using namespace std; void divide(int x,int y){ if (y == 0){ throw x;//抛出 int 类型异常 //异常直接跨越函数,类似于return语句,不执行接下来的语句 } cout << "divide结果:" << x / y << endl; } void myDivide(int x, int y){ try{ divide(x, y); } catch (...){ cout << "我接受了divide的异常,但是我没有处理,我继续向上抛出" << endl; throw;//接受异常后可以不处理,继续抛出 } } int _tmain(int argc, _TCHAR* argv[]) { try{ divide(10 , 2); divide(100 , 0); //myDivide(1, 0);//跨越函数的实验 } catch (int e){ cout << e << "被零整除" << endl; } catch (...){//其他未知类型的异常 cout << "其他未知类型异常" << endl; } return 0; }
2.栈解旋
执行throw语句后,相当于 return ,但是不是,会调用析构函数 释放掉栈空间
// 异常_栈解旋.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> using namespace std; class Test{ public: Test(int a = 0, int b = 0){ this->a = a; this->b = b; cout << "构造函数do" << endl; } ~Test(){ cout << "析构函数do\n"; } private: int a; int b; }; void myDivide(){ Test t1(1, 2), t2(3, 4); cout << "myDivide 要发生异常啦~ " << endl; throw 1; } int _tmain(int argc, _TCHAR* argv[]) { try{ myDivide(); } catch (int a){ cout << "int型异常" << endl; } catch (...){ cout << "未知异常" << endl; } return 0; }
3.异常的接口声明
1)为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常累成,例如:
void func() throw(A,B,C,D);//这个函数func()能够且只能抛出类型A B C D及其子类型的异常
2)如果在函数声明中没有包含异常接口声明,则该函数可以抛出任何类型的异常,例如:
void func();
3)一个不抛出任何类型异常的函数可以声明为:
void func() throw();
4)如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpercted函数会被调用,该函数默认行为调用terminate函数终止程序。
4.异常变量的声明周期
// 异常_栈解旋.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> using namespace std; class BadSrcType{ public: BadSrcType(){ cout << "BadSrcType构造函数do" << endl; } BadSrcType(const BadSrcType &obj){ cout << "BadSrcType拷贝构造函数do" << endl; } ~BadSrcType(){ cout << "BadSrcType析构函数do\n"; } }; class BadDesType{ public: BadDesType(){ cout << "BadDesType构造函数do" << endl; } BadDesType(const BadDesType &obj){ cout << "BadDesType拷贝构造函数do" << endl; } ~BadDesType(){ cout << "BadDesType析构函数do\n"; } }; class BadProType{ public: BadProType(){ cout << "BadProType构造函数do" << endl; } BadProType(const BadProType &obj){ cout << "BadProType拷贝构造函数do" << endl; } ~BadProType(){ cout << "BadProType析构函数do\n"; } }; void my_strcpy(char *to,char *from){ if (from == NULL){ throw BadSrcType();//会产生一个匿名对象 } if (to == NULL){ throw BadDesType(); } if (*from=='a'){ cout << "开始BadProType类型异常" << endl; throw BadProType();//适用于方式一和二 //throw new BadProType;//适用于方式三 } while (*from!='\0'){ *to = *from; to++; from++; } *to = '\0'; } int main() { int ret = 0; char buf1[] = "abcdefg"; char buf2[1024] = { 0 }; try{ my_strcpy(buf2,buf1); } //结论1:如果接收异常的时候使用异常变量 则进行拷贝构造异常变量 catch (BadSrcType e){//接匿名对象,并初始化e,此时匿名对象转正,不会调用匿名对象的析构函数 cout << "BadSrcType类型异常" << endl; } catch (BadDesType e){ cout << "BadDesType类型异常" << endl; } catch (BadProType e){ cout << "BadProType类型异常" << endl; } catch (...){ cout << "未知异常" << endl; } //方式二:用引用接收异常 //结论二:使用引用的话 会使用throw时候的那个对象 //catch (BadSrcType &e){//接匿名对象,并初始化e,此时匿名对象转正,不会调用匿名对象的析构函数 // cout << "BadSrcType类型异常" << endl; //} //catch (BadDesType &e){ // cout << "BadDesType类型异常" << endl; //} //catch (BadProType &e){ // cout << "BadProType类型异常" << endl; //} //catch (...){ // cout << "未知异常" << endl; //} //方式三:用指针来接 //结论三:指针可以和引用/元素 写在一块,但是元素和引用不能写在一块 //catch (BadSrcType *e){//接匿名对象,并初始化e,此时匿名对象转正,不会调用匿名对象的析构函数 // cout << "BadSrcType类型异常" << endl; // delete e;//在底层函数里new,在上层函数里delete。不安全 //} //catch (BadDesType *e){ // cout << "BadDesType类型异常" << endl; // delete e; //} //catch (BadProType *e){ // cout << "BadProType类型异常" << endl; // delete e; //} //catch (...){ // cout << "未知异常" << endl; //} //结论:最适合的方法是用引用来接 return 0; }方式一:
方式二:
方式三:
相关文章推荐
- C语言易错的优先级
- 比较大数的大小(10**6) c++ python
- 双向链表(c++实现)
- /c++赋值运算符为什么要返回引用
- 条款二:最好使用c++转型操作符
- C++编译器与链接器的工作原理
- CSV文件的使用-写入/写出(C++/Python)
- Bill学C++ 第二季:mutable 关键字
- Bill学C++ 第一季:const 详解
- c++ delete的用法小结
- Qt C++GUI Qt4 编程书中网址
- C语言中数组与指针辨析
- C++中模板与用C语言中实现模板
- [C++]queue简单实现--关于模板
- C++智能指针作为成员变量的用法
- 举例解析设计模式中的工厂方法模式在C++编程中的运用
- 单链表(c++实现)
- 统计某个字符串中的标点符号数(c++11)
- 更安全的C语言字符串处理函数
- VC++调用C#生成DLL的两种方法!