异常类构建:
- 异常的类型可以是自定义 类类型
- 对于 类类型异常 的匹配依旧是至上而下严格匹配
- 赋值兼容性原则 在异常匹配中依然适用
- 一般而言
– 匹配子类异常的 catch 放在上部
– 匹配父类异常的 catch 放在下部 - 现代c++库必然包所依赖的异常类族
- 异常类中的接口定义
class Exception
{
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() = 0;
};
设计原则
–在可服用代码库设计时,尽量适用面向对象技术进行架构,尽量使用异常处理机制 分离正常逻辑和异常逻辑现代c++库中必然包含充要的异常类族
- 所有库中的数据结构都依赖于异常机制
- 异常机制能够分离库中代码的正常逻辑和异常逻辑
以下为实现自己的异常库MyLib部分代码
file:Exception.h
namespace MyLib {
#define THROW_EXCEPTION(e, m) (throw e(m, __FILE__, __LINE__))
//为顶层 抽象父类
class Exception
{
protected:
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() = 0;//纯虚析构函数 等待子类来完成
//但凡定义了 析构函数,不管这个析构函数是不是纯虚函数,必须提供实现
};
//计算异常
class ArithmeticException : public Exception
{
public:
ArithmeticException():Exception(NULL){}
ArithmeticException(const char* message):Exception(message){}
ArithmeticException(const char* file,int line):Exception(file,line){}
ArithmeticException(const char* message,const char* file, int line):Exception(message,file,line){}
ArithmeticException(const ArithmeticException& e):Exception(e){}
ArithmeticException& operator= (const ArithmeticException& e)
{
Exception::operator =(e);
return *this;
}
};
}
file:Exception.cpp
namespace MyLib
{
void Exception::init(const char *message, const char *file, int line)
{
//参数message是一个指针,指向的字符串 有可能 在栈上、堆上、全局数据区,没法控制指向的字符串的声明周期.
//所以说这样是不安全的(m_message = message),可能被释放,所以需要拷贝一份信息.
m_message = strdup(message);//字符串复制一份到堆空间,m_message指向对空间的字符串
if(file != NULL)
{
char sl[16] = {0};
itoa(line,sl,10);
m_location = static_cast<char*>(malloc(strlen(file)+strlen(sl)+2));
m_location = strcpy(m_location,file);
m_location = strcat(m_location,":");
m_location = strcat(m_location,sl);
}
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);
}
}
file:main.cpp
#include <iostream>
#include "Exception.h"
using namespace std;
using namespace MyLib;
int main()
{
cout << "Hello World!" << endl;
try
{
//throw Exception("test",__FILE__,__LINE__);
//THROW_EXCEPTION(NullPointerException,"test");
//扔出子类对象,子类对象可以出现在任何父类需要对象的地方
THROW_EXCEPTION(ArithmeticException,"test");
}
catch(const ArithmeticException& e)
{
cout<<"catch(const ArithmeticException& e)"<<endl;
cout<< e.message()<<endl;
cout<< e.location()<<endl;
}
catch(const Exception& e)//父类放在最后
{
cout<<"catch(const Exception& e)"<<endl;
cout<< e.message()<<endl;
cout<< e.location()<<endl;
}
return 0;
运行结果:
Hello World!
catch(const ArithmeticException& e)
test
..\MyLib\main.cpp:18
学习内容来自D.T.Software的数据结构课程,希望可以和大家一起学习