从零开始学C++(8)----异常

目录

1.异常处理方式

2.栈解旋

3.标准异常

4.静态断言


1.异常处理方式

        在C++中,如果函数在调用时发生异常,异常通常会被传递给函数的调用者进行处理,而不在发生异常的函数内部处理。如果函数调用者也不能处理异常,则异常会继续向上一层调用者传递,直到异常被处理为止,如果最终异常没有被处理,则C++运行系统就会捕捉异常,终止程序运行。

        C++的异常处理机制使得异常的引发和处理不必再同一函数中完成,函数的调用者可以在1适当的位置对函数抛出的异常进行处理,这样底层的函数可以着重解决具体的业务问题,而不必考虑对异常的处理。

        C++的异常处理通过throw关键字和try...catch语句结构实现,通常情况下,被调用的函数如果发生异常,就通过throw关键字1抛出异常,而函数上层调用者通过try...catch语句检测,捕获异常并对异常进行处理。

throw 表达式;

        throw后面的表达式可以是常量,变量或对象。如果函数调用中出现异常,就可以通过throw将表示异常的表达式抛给它的调用者。

        函数调用者通过try...catch语句捕获,处理异常,格式如下:

try
{
    ...
}
catch(异常类型1)
{
    ...
}
catch(异常类型2)
{
    ...
}
catch(异常类型n)
{
    ...
}

        try语句块用于检测可能发生异常的代码,如果这段代码抛出了异常,则catch语句会依次对抛出的异常1进行类型匹配,如果某个catch语句中的异常类型与抛出的异常类型相同,则该catch语句就捕获异常并对异常进行处理。

  1. 一个try...catch语句只能有try语句块,但可以有多个catch语句块。以便与不同的异常类型匹配,catch语句必须有参数,如果try语句块中的代码抛出了异常,无论抛出的值是什么,只要异常的类型与catch语句的参数类型匹配,异常就会被catch语句捕获,最后一个catch语句参数为...符号,表示可以捕获任意类型的异常。
  2. 一旦某个catch语句捕获到了异常,后面的catch语句将不再被执行。
  3. try和catch语句块中的代码必须使用大括号括起来。
  4. try...catch语句不能单独使用。
  5. 如果try语句块中的某一行代码抛出了异常,则无论异常是否被处理,抛出异常的语句后面的代码都不再被执行。
#include<iostream>
#include<fstream>
using namespace std;
class AbstractException
{
public:
    virtual void printErr()=0;
};
class FileException:public AbstractException
{
public:
    virtual void printErr()
    {
        cout<<"错误,文件不存在"<<endl;
    }
};
class DivideException:public AbstractException
{
public:
    virtual void printErr()
    {
        cout<<"错误,除零异常"<<endl;
    }
};
void readFile()
{
    ifstream ifs("log.txt");
    if(!ifs)
    {
        throw FileException();
    }
    ifs.close();
}
void divide()
{
    int num1=100;
    int num2=2;
    if(num2==0)
    {
        throw DivideException();
    }
    int ret=num1/num2;
    cout<<"两个数相除结果:"<<ret<<endl;
}
int main()
{
    try
    {
        readFile();
        divide();
    }
    catch(FileException& fex)
    {
        fex.printErr();
    }
    catch(DivideException& dex)
    {
        dex.printErr();
    }
    catch(...)
    {
        cout<<"处理其他异常"<<endl;
    }
    cout<<"程序运行结束"<<endl;
    return 0;
}

2.栈解旋

        C++不仅能处理各种不同类型的异常,还可以在异常处理前释放所有局部对象。从进入try语句块开始到异常被抛出之前,在栈上创建的所有对象都会被析构,析构的顺序与构造的顺序相反,这一过程称为栈解旋或栈自旋。

#include<iostream>
using namespace std;
class Shape
{
public:
    Shape();
    ~Shape();
    static int count;
};
int Shape::count=0;
Shape::Shape()
{
    count++;
    if(Shape::count==3)
        throw "纸张画不下了!!";
    cout<<"Shape构造函数"<<endl;
}
Shape::~Shape()
{
    cout<<"Shape析构函数"<<endl;
}
int main()
{
    Shape circle;
    try
    {
        int num=2;
        cout<<"纸张可画图个数:"<<num<<endl;
        Shape rectangle;
        Shape triangle;
    }
    catch(const char* e)
    {
        cout<<e<<endl;
    }
    return 0;
}

3.标准异常

        C++提供了一组标准异常类,这些类以exception为根基类,程序中抛出的所有标准异常都继承自exception类,exception类定义在exception头文件中,定义如下:

class exception
{
public:
    exception() noexcept;
    exception(const exception&) noexcept;
    exception& operator=(const exception&) noexcept;
    virtual ~exception();
    virtual const char* what() const noexcept;
};
#include<iostream>
using namespace std;
class Animal
{
public:
    virtual void speak();
};
void Animal::speak()
{
    cout<<"动物叫声"<<endl;
}
class Cat:public Animal
{
public:
    virtual void speak();
};
void Cat::speak()
{
    cout<<"小猫喵喵叫"<<endl;
}
int main()
{
    Animal animal;
    Animal& ref=animal;
    ref.speak();
    try
    {
        Cat& cat=dynamic_cast<Cat&>(ref);
        cat.speak();
    }
    catch(bad_cast& ex)
    {
        cout<<ex.what()<<endl;
    }
    return 0;
}

        在exception类定义中,noexcept关键字表示函数不抛出异常。

4.静态断言

        断言是编程中常用的一种调试手段。在C++11之前,C++使用assert()宏进行断言,但是它只能在程序运行时期执行,不运行时无法检测到错误,C++11引用静态断言static_assert,格式如下:

static_assert(常量表达式,提示字符串);

        在执行断言时,编译器首先检测“常量表达式的值”,若为真,程序完成编译,为假生成一个错误提示为第二个参数。

#include<iostream>
using namespace std;
template<typename T,typename U>
void func(T& t,U& u)
{
    static_assert(sizeof(t)==sizeof(u),
            "the parameters must be the same width.");
}
int main()
{
    int x=100;
    int y=20;
    char ch='a';
    func(x,y);
    func(x,ch);
    return 0;
}
error: static assertion failed: the parameters must be the same width.

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值