花呗套现方法与步骤:每日一课——【异常处理】c++标准异常处理:原理+方法

兰溪之窗3周前为民直通车21
花呗套现方法与步骤:异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。函数的异常声明列表为了增强程序的可读性和可维护性,使程序员在使用一个函数时就能看出这个函数可能会拋出哪些异常,C++ 允许在函数声明和定义时,加上它所能拋出的异常的列表,具体写法如下:void func() throw (int, double, A, B, C);
或void func() throw (int, double, A, B, C){...}
上面的写法表明 func 可能拋出 int 型、double 型以及 A、B、C 三种类型的异常。异常声明列表可以在函数声明时写,也可以在函数定义时写。如果两处都写,则两处应一致。

如果异常声明列表如下编写:void func() throw ();
则说明 func 函数不会拋出任何异常。

一个函数如果不交待能拋出哪些类型的异常,就可以拋出任何类型的异常。

函数如果拋出了其异常声明列表中没有的异常,在编译时不会引发错误,但在运行时, Dev C++ 编译出来的程序会出错;用 Visual Studio 2010 编译出来的程序则不会出错,异常声明列表不起实际作用。异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw。throw:当问题出现时,程序会抛出一个异常。这是通过使用throw关键字来完成的。catch:在您想要处理问题的地方,通过异常处理程序捕获异常。catch关键字用于捕获异常。try:try块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。如果有一个块抛出一个异常,捕获异常的方法会使用try和catch关键字。try 块中放置可能抛出异常的代码,try 块中的代码被称为保护代码。使用 try/catch 语句的语法如下所示:try
{
// 保护代码
}catch( ExceptionName e1 )
{
// catch 块
}catch( ExceptionName e2 )
{
// catch 块
}catch( ExceptionName eN )
{
// catch 块
}
如果try块在不同的情境下会抛出不同的异常,这个时候可以尝试罗列多个catch语句,用于捕获不同类型的异常。C++异常处理基本语法C++ 通过 throw 语句和 try...catch 语句实现对异常的处理。throw 语句的语法如下:throw 表达式;
该语句拋出一个异常。异常是一个表达式,其值的类型可以是基本类型,也可以是类。try...catch 语句的语法如下:try {
语句组
}
catch(异常类型) {
异常处理代码
}
...
catch(异常类型) {
异常处理代码
}
catch 可以有多个,但至少要有一个。

不妨把 try 和其后{}中的内容称作“try块”,把 catch 和其后{}中的内容称作“catch块”。抛出异常您可以使用throw语句在代码块中的任何地方抛出异常。throw 语句的操作数可以是任意的表达式,表达式的结果的类型决定了抛出的异常的类型。以下是尝试除以零时抛出异常的实例:double division(int a,int b)
{
if( b ==0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
捕获异常catch块跟在try块后面,用于捕获异常。您可以指定想要捕捉的异常类型,这是由 catch 关键字后的括号内的异常声明决定的。try...catch 语句的执行过程是:执行 try 块中的语句,如果执行的过程中没有异常拋出,那么执行完后就执行最后一个 catch 块后面的语句,所有 catch 块中的语句都不会被执行;如果 try 块执行的过程中拋出了异常,那么拋出异常后立即跳转到第一个“异常类型”和拋出的异常类型匹配的 catch 块中执行(称作异常被该 catch 块“捕获”),执行完后再跳转到最后一个 catch 块后面继续执行。try
{
// 保护代码
}catch( ExceptionName e )
{
// 处理 ExceptionName 异常的代码
}
上面的代码会捕获一个类型为ExceptionName的异常。如果您想让 catch 块能够处理 try 块抛出的任何类型的异常,则必须在异常声明的括号内使用省略号 ...,如下所示:try
{
// 保护代码
}catch(...)
{
// 能处理任何异常的代码
}
下面是一个实例,抛出一个除以零的异常,并在 catch 块中捕获该异常。#include iostream
using namespace std;

double division(int a,int b)
{
if( b ==0 )
{
throw "Division by zero condition!";
}
return (a/b);
}

int main ()
{
int x =
int y =
double z =

try {
z = division(x, y);
cout z endl;
}catch (const char* msg) {
cerr msg endl;
}

return 0;
}
由于我们抛出了一个类型为const char*的异常,因此,当捕获该异常时,我们必须在 catch 块中使用 const char*。当上面的代码被编译和执行时,它会产生下列结果:Division by zero condition!
如果拋出的异常没有被 catch 块捕获,例如,将catch(int e),改为catch(char e),当输入的 n 为 0 时,拋出的整型异常就没有 catch 块能捕获,这个异常也就得不到处理,那么程序就会立即中止,try...catch 后面的内容都不会被执行。C++ 标准的异常C++ 提供了一系列标准的异常,定义在 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:下表是对上面层次结构中出现的每个异常的说明:下面分别介绍以上几个异常类。本节程序的输出以 Visual Studio 2010为准,Dev C++ 编译的程序输出有所不同。1) bad_typeid使用 typeid 运算符时,如果其操作数是一个多态类的指针,而该指针的值为 NULL,则会拋出此异常。2) bad_cast在用 dynamic_cast 进行从多态基类对象(或引用)到派生类的引用的强制类型转换时,如果转换是不安全的,则会拋出此异常。程序示例如下:#include iostream
#include stdexcept
using namespace std;
int main()
{
try {
char * p = new char[0x7fffffff]; //无法分配这么多空间,会抛出异常
}
catch (bad_alloc e) {
cerr e.what() endl;
}
return 0;
}
程序的输出结果如下:Bad dynamic_cast!
在 PrintObj 函数中,通过 dynamic_cast 检测 b 是否引用的是一个 Derived 对象,如果是,就调用其 Print 成员函数;如果不是,就拋出异常,不会调用 Derived::Print。3) bad_alloc在用 new 运算符进行动态内存分配时,如果没有足够的内存,则会引发此异常。程序示例如下:#include iostream
#include stdexcept
using namespace std;
int main()
{
try {
char * p = new char[0x7fffffff]; //无法分配这么多空间,会抛出异常
}
catch (bad_alloc e) {
cerr e.what() endl;
}
return 0;
}
程序的输出结果如下:bad allocation
ios_base::failure
在默认状态下,输入输出流对象不会拋出此异常。如果用流对象的 exceptions 成员函数设置了一些标志位,则在出现打开文件出错、读到输入流的文件尾等情况时会拋出此异常。此处不再赘述。4) out_of_range用 vector 或 string 的 at 成员函数根据下标访问元素时,如果下标越界,则会拋出此异常。例如:#include iostream
#include stdexcept
#include vector
#include string
using namespace std;
int main()
{
vectorint v(10);
try {
v.at(100) = 100; //拋出 out_of_range 异常
}
catch (out_of_range e) {
cerr e.what() endl;
}
string s = "hello";
try {
char c = s.at(100); //拋出 out_of_range 异常
}
catch (out_of_range e) {
cerr e.what() endl;
}
return 0;
}
程序的输出结果如下:invalid vector subscript
invalid string position
如果将v.at(100)换成v[100],将s.at(100)换成s[100],程序就不会引发异常(但可能导致程序崩溃)。因为 at 成员函数会检测下标越界并拋出异常,而 operator[] 则不会。operator [] 相比 at 的好处就是不用判断下标是否越界,因此执行速度更快。定义新的异常您可以通过继承和重载exception类来定义新的异常。下面的实例演示了如何使用 std::exception 类来实现自己的异常:#include iostream
#include exception
using namespace std;

struct MyException :public exception
{
const char * what ()const throw ()
{
return "C++ Exception";
}
};

int main()
{
try
{
throw MyException();
}
catch(MyException e)
{
std::cout "MyException caught" std::endl;
std::cout e.what() std::endl;
}
catch(std::exception e)
{
//其他的错误
}
}
这将产生以下结果:MyException caught
C++ Exception
在这里,what()是异常类提供的一个公共方法,它已被所有的异常类重载。这将返回异常产生的原因。想学习C/C++的朋友,如果你没有思绪,不知道如何着手学习,欢迎点击下方了解更多跟着小编我免费学习噢。