我们在之前学习了 C++ 中有关异常的知识,现在我们来重新回顾下。那么异常的格式是什么呢?便是 try … catch …;try 语句处理正常的代码逻辑,而 catch 语句则处理异常情况,try 语句中的异常由对应的 catch 语句处理。格式如下
try { double r = divide(1, 0); } catch(...) { cout << "Divided by zero ..." << endl; }
在 C++ 中,通过 throw 语句抛出异常信息。throw 抛出的异常必须被 catch 处理,当前函数如果能处理异常,程序将继续往下执行;如果当前函数无法处理异常则函数停止执行并返回。未被处理的异常会顺着函数调用栈向上传播,直到被处理为止,否则程序将停止执行。如下
同一个 try 语句可以跟上多个 catch 语句。catch 语句可以定义具体处理的异常类型,不同类型的异常由不同的 catch 语句负责处理;try 语句中可以抛出任何类型的异常,catch(…) 用于处理所有类型的异常,任何异常都只能被捕获(catch)一次。异常处理的匹配规则如下
异常的类型可以是自定义类类型,对于类类型异常的匹配依旧是至上而下严格匹配,赋值兼容性原则在异常匹配中依然适用。一般而言:匹配子类异常的 catch 放在上部,匹配父类异常的 catch 放在下部。现代 C++ 库中必然包含充要的异常类族,因为异常类是数据结构类所依赖的“基础设施”!举个例子,如果我们在申请内存失败时便要但会一个内存不足的异常。异常类如下图所示
下来我们来看看异常类功能定义,如下
下来我们来创建一个异常类族,代码如下
Exception.h 源文件
#ifndef EXCEPTION_H#define EXCEPTION_H #include "Object.h" namespace DTLib { class Exception : public Object { private: char* m_message; char* m_location; void init(const char* message, const char* file, int line); public: Exception(const char* message); Exception(const char* file, int line); Exception(const char* message, const char* file, int line); Exception(const Exception& e); Exception& operator= (const Exception& e); virtual const char* message() const; virtual const char* location() const; virtual ~Exception(); }; #endif // EXCEPTION_H
Exception.cpp 源码如下
#include "Exception.h"#include <cstring> #include <cstdlib> using namespace std; namespace DTLib { void Exception::init(const char* message, const char* file, int line) { m_message = strdup(message); if( file != NULL ) { char s1[16] = {0}; itoa(line, s1, 10); m_location = static_cast<char*>(malloc(strlen(file) + strlen(s1) + 2)); m_location = strcpy(m_location, file); m_location = strcat(m_location, ":"); m_location = strcat(m_location, s1); } else { m_location = NULL; } } Exception::Exception(const char* message) { init(message, NULL, 0); } Exception::Exception(const char* file, int line) { init(NULL, file, line); } Exception::Exception(const char* message, const char* file, int line) { init(message, file, line); } Exception::Exception(const Exception& e) { m_message = strdup(e.m_message); m_location = strdup(e.m_location); } Exception& Exception::operator= (const Exception& e) { if( this != &e ) { free(m_message); free(m_location); m_message = strdup(e.m_message); m_location = strdup(e.m_location); } return *this; } const char* Exception::message() const { return m_message; } const char* Exception::location() const { return m_location; } Exception::~Exception() { free(m_message); free(m_location); } }
main.cpp 源文件如下
#include <iostream>#include "Exception.h" using namespace std; using namespace DTLib; int main() { try { throw Exception("test", __FILE__, __LINE__); } catch(const Exception& e) { cout << "catch(const Exception& e)" << endl; cout << e.message() << endl; cout << e.location() << endl; } return 0; }
下来我们来看看编译结果
我们看到抛出了一个异常,它的文件名是 test,行号是 11 行。我们可以在 Exception.h 头文件添加一个宏,用来显示文件名及行号,定义如下
#define THROW_EXCEPTION(e, m) (throw e(m, __FILE__, __LINE__))
然后将 mian.cpp 中的 throw 语句中的抛异常改为下面这样
THROW_EXCEPTION(Exception, "test");
编译结果如下
我们看到效果是一样的。那么在可复用代码库设计时,尽量使用卖你想对象技术进行架构,尽量使用异常处理机制分类正常逻辑和异常逻辑。通过今天对异常类的学习,总结如下:1、C++ 中国直接支持异常处理的概念,try … catch … 是 C++ 中异常处理的专用语句;2、try 语句处理的是正常代码逻辑,catch 语句处理的是异常情况;3、同一个 try 语句可以跟上多个 catch 语句,异常处理必须严格匹配,不进行任何的类型转换;4、现代 C++ 库必然包含充要的异常类族,所有库中的数据结构都依赖于异常机制;5、异常机制能够分离库中代码的正常逻辑个异常逻辑。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/196019.html