异常处理的基本知识(异常抛出处理过程简介)
异常处理的基本知识(异常抛出处理过程简介)异常处理是程序设计中除调试之外的另一种错误处理方法。语法解释: 用类型映射,即在告诉编译器,即使知道一个对象的确切类型,还是可以假定认为他是另外一种类型。【危险、易出错】解决方法: C 用保留字dynamic_cast、const_cast、static_cast、reinterpret_cast提供统一的类型映射语法,为需要进行动态映射时提供了一个解决问题的可能。
RTTI:(Run-timeType Identification )运行时类型识别,即在程序运行时,通过某一对象的指针确定该对象的类型。
RTTI与引用RTTI必须和引用一起工作。指针与引用存在明显的不同,因为引用总是有编译器逆向引用,而一个指针的类型或他只想的类型可能要检测。
RTTI与多重继承RTTI是一个功能非常强大的功能,对:于面向对象的编程方法,如果在类继承时使用了virtual虚基类,RTTI仍然可以准确地获取对象在运行时的信息。
RTTI映射语法问题:
用类型映射,即在告诉编译器,即使知道一个对象的确切类型,还是可以假定认为他是另外一种类型。【危险、易出错】
解决方法:
C 用保留字dynamic_cast、const_cast、static_cast、reinterpret_cast提供统一的类型映射语法,为需要进行动态映射时提供了一个解决问题的可能。
语法解释:
- dynamic_cast : 用于安全类型的向下映射。
- const_cast : 用于映射常量和变量。
- static_cast : 为了行为良好和行为较好使用的映射,如向上转型和类型自动转换。
- reinterpret_cast : 将某一类型映射回原有类型的使用。
异常处理是程序设计中除调试之外的另一种错误处理方法。
缺点:会引起代码膨胀,增加程序阅读困难。
优点:异常处理不但可以对系统错误做出反应,还可以对认为制造的错误做出反应并处理。
语法:
try //捕获throw所抛出的异常 { throw (type obj) ; //抛出异常; } catch (type obj) //异常处理器:可处理任何异常,即销毁异常信号 { //记录并输出异常信息 } catch(...) //...表示all abnormal,销毁任何异常信号。 { //可以处理任何类型异常,即输出未知异常。 }
实例:
#include "stdafx.h" #include "iostream" #include "string.h" class CcustomError //异常类 { private: int m_ErrId; char m_ErrInfo[255]; public: CCustomError() { m_ErrId =1 ; strcpy(m_ErrInfo "出现异常!"); } int GetErrorId(){return m_ErrId;} char *GetErrorInfo(){return m_ErrInfo} }; int main(int argc char* argv[]) { try { throw(new CCustomError()); } catch(CCustomError* error) { cout<<"异常Id:"<<error->GetErrorId()<<endl; cout<<"异常信息:"<<error->GetErrorInfo<<endl; } catch(char* error) { cout<<"异常信息:"<<error<<endl; } catch(...) { cout<<"未知异常信息!"<<endl; throw;//在未知异常时,往往需要从新抛出,以便其进入更高层次的异常处理环境。 } return 0; } 异常匹配
异常抛出流程:异常处理系统会根据异常处理器的顺序找到最近的异常处理块,并不会搜索更多的异常处理块。
异常匹配并不要求异常与异常处理器进行完美匹配,一个对象或一个派生类对象的引用将与积累处理器进行匹配。若抛出的是类对象的指针。则指针会匹配相应的对象类型,但不会自动转换成其他对象类型。
例子:基类处理器如何捕获派生类异常
#inlcude "stdafx.h" #include "iostream" class CExcept //创建异常基类CExcept { public: virtual char *GetError(){return "基类处理器";} //定义char类型函数指针变量 }; class CDerive: public CExcept //创建派生类CDerive { public: char *GetError(){return "派生类处理器";}//定义派生类处理器错误函数 char 类型函数指针变量 }; int main (int argc char* argv[])//定义带参主函数 { try //捕获异常-抛出异常 { throw CDerive(); } catch(CExcept) //基类异常处理器--销毁基类异常 { cout<<"进入基类处理器\n"<<endl; } catch(CDerive) //派生类异常处理器--销毁异常 { cout<<"进入派生类处理器\n"<<endl; } return 0; //返回0 } 标准异常
标准异常指C 标准库中存在的异常类型,库中定义了一个公共的基类exception。标准异常都派生自此基类。基类包含必要的多态性函数提供异常描述,可以被重载。
namespace std //标准异常分类 { //exception 派生 class logic_error ; //违反逻辑错误,在程序运行前可以检测出来 //logic_error 派生 class domain_error ;//违反了前置条件 class invalid_argument; //指出函数的一个无效参数 class length_error ; //指出有一个超过类型size_t的最大可表现值长度的对象的企图 class out_of_range ; //参数越界 class bad_cast: //在运行时类型识别中有个无效的dynamic_cast 表达式 class bad_typeid; //报告在表达式typeid(*p)中有个空指针p //exception 派生 class runtime_error ;//运行时错误,仅在程序运行中检测到 //runtime_error 派生 class rang_error ; //违反后置条件 class overflow_error ; //报告一个算术溢出 class bad_alloc; //存储分配错误 } class exception //exception类的原型 { public: exception() throw() ; exception(const exception& rhs) throw(); exception& operator = (const exception& rhs) throw(); virtual ~exception() throw(); virtual const char *what() const throw(); }
实例练习:
三角形面积s=sqrt(p*(p-a)*(p-b)*(p-c)) p=(a b c)/2;
求三角形面积程序,并可以实现捕获以下异常:
1.边长不正确,要求应该是正数;
2.边长组合不正确,要求任意两边之和大于第三边。
#include "stdafx.h" #include "iostream" #include "math.h" #include "exception" using namespace std; int main(int argc char* argv[]) //主函数 { int a; int b; int c; int d=0; double p; double s; try { cout << "请输入第一条边长a:"; cin >> a; cout << endl; cout << "请输入第二条边长b: "; cin >> b; cout << endl; cout << "请输入第三条边长c: "; cin >> c; cout << endl; if (a < 0 || b < 0 || c < 0) { throw "边长不正确,应该为正数"; } else if (a b <= c || b c <= a || c a <= b) { throw "边长组合不正确,应该任意两边之和大于第三边!"; } } catch (char *error) { cout << error<<endl; } p = (a b c) / 2; s = sqrt(p*(p - a)*(p - b)*(p - c)); cout << "三角形的面积s=:" << s << endl; system("pause"); return 0; }
结果如下: