1 异常类构建
- 异常的类型也可以是自定义类型
- 对于类类型异常的匹配依旧是至上而下严格匹配的
- 赋值兼容性原则在异常匹配中依然适用
- 一般而言:
- 匹配子类异常的catch放在上部
- 匹配父类异常的catch放在下部
设计原则: 在可复用代码库设计时,尽量使用面向对象技术进行架构,尽量使用异常处理机制分离正常逻辑和异常逻辑。
2 继承关系图和接口实现
异常类继承关系图
异常类功能定义
| 异常类 | 功能定义 |
|---|---|
| ArithmeticException | 计算异常 |
| NullPointerException | 空指针异常 |
| IndexOutOfBoundsException | 越界异常 |
| NoEnoughMemoryException | 内存不足异常 |
| InvalidParameterException | 参数错误异常 |
| InvalidOperationException | 不合法操作异常(成员函数调用时,如果状态不正确则抛出异常) |
异常类中的接口定义
class Exception : public Object
{
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;
};
3 代码实现
Exception.h
#ifndef EXCEPTION_H
#define EXCEPTION_H
#include "Object.h"
namespace LemonLib
{
/*
* 这里直接抛异常对象即可,不要使用new创建异常对象
*/
#define THROW_EXCEPTION(e, m) (throw e(m, __FILE__, __LINE__))
class Exception : public Object
{
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);
/*
* 设计为虚函数的原因:方便异常捕获时,直接用父类型进行匹配,调用该函数时可以进行动态类型识别。
* const函数:可能会被const对象调用,因此需要加上const。这里应该说必须加,因为对异常进行捕获时,
* 我们通常会写出类似的代码:catch (const Exception& e)。
*/
virtual const char* message() const;
virtual const char* location() const;
/* 1.成为抽象类。2.使用父类指针释放子类对象时,可以调用子类的析构函数。 */
virtual ~Exception() = 0;
};
class ArithmeticException : public Exception
{
public:
ArithmeticException() : Exception(0){} /* 直接调用父类的构造函数即可 */
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;
}
};
class NullPointerException : public Exception
{
public:
NullPointerException() : Exception(0){}
NullPointerException(const char* message) : Exception(message){}
NullPointerException(const char* file, int line) : Exception(file, line){}
NullPointerException(const char* message, const char* file, int line) : Exception(message, file, line){}
NullPointerException(const NullPointerException& e) : Exception(e){}
NullPointerException& operator = (const NullPointerException& e)
{
Exception::operator =(e);
return *this;
}
};
class IndexOutOfBoundsException : public Exception
{
public:
IndexOutOfBoundsException() : Exception(0){}
IndexOutOfBoundsException(const char* message) : Exception(message){}
IndexOutOfBoundsException(const char* file, int line) : Exception(file, line){}
IndexOutOfBoundsException(const char* message, const char* file, int line) : Exception(message, file, line){}
IndexOutOfBoundsException(const IndexOutOfBoundsException& e) : Exception(e){}
IndexOutOfBoundsException& operator = (const IndexOutOfBoundsException& e)
{
Exception::operator =(e);
return *this;
}
};
class NoEnoughMemoryException : public Exception
{
public:
NoEnoughMemoryException() : Exception(0){}
NoEnoughMemoryException(const char* message) : Exception(message){}
NoEnoughMemoryException(const char* file, int line) : Exception(file, line){}
NoEnoughMemoryException(const char* message, const char* file, int line) : Exception(message, file, line){}
NoEnoughMemoryException(const NoEnoughMemoryException& e) : Exception(e){}
NoEnoughMemoryException& operator = (const NoEnoughMemoryException& e)
{
Exception::operator =(e);
return *this;
}
};
class InvalidParameterException : public Exception
{
public:
InvalidParameterException() : Exception(0){}
InvalidParameterException(const char* message) : Exception(message){}
InvalidParameterException(const char* file, int line) : Exception(file, line){}
InvalidParameterException(const char* message, const char* file, int line) : Exception(message, file, line){}
InvalidParameterException(const InvalidParameterException& e) : Exception(e){}
InvalidParameterException& operator = (const InvalidParameterException& e)
{
Exception::operator =(e);
return *this;
}
};
class InvalidOperationException : public Exception
{
public:
InvalidOperationException() : Exception(0){}
InvalidOperationException(const char* message) : Exception(message){}
InvalidOperationException(const char* file, int line) : Exception(file, line){}
InvalidOperationException(const char* message, const char* file, int line) : Exception(message, file, line){}
InvalidOperationException(const InvalidOperationException& e) : Exception(e){}
InvalidOperationException& operator = (const InvalidOperationException& e)
{
Exception::operator =(e);
return *this;
}
};
}
#endif // EXCEPTION_H
Exception.cpp
#include "Exception.h"
#include <cstring>
#include <cstdlib>
namespace LemonLib
{
void Exception::init(const char* message, const char* file, int line)
{
/* 为了保证message所指向空间的生命周期和异常对象相同,这里我们需要重新开辟空间 */
m_message = message ? strdup(message) : NULL;
if (file != NULL)
{
char str_line[16] = {0};
itoa(line, str_line, 10); /* 10的含义为按10进制进行转换 */
m_location = static_cast<char*>(malloc(strlen(file) + strlen(str_line) + 2));
if (m_location != NULL)
{
strcpy(m_location, file); /* 结尾会复制\0 */
strcat(m_location, ":"); /* 结尾会复制\0 */
strcat(m_location, str_line);
}
}
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 = e.m_message ? strdup(e.m_message) : NULL;
m_location = e.m_location ? strdup(e.m_location) : NULL;
}
Exception& Exception::operator = (const Exception& e)
{
if (this != &e) /* 防止自赋值 */
{
free(m_message);
free(m_location);
m_message = e.m_message ? strdup(e.m_message) : NULL;
m_location = e.m_location ? strdup(e.m_location) : NULL;
}
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 "Object.h"
#include "Exception.h"
using namespace std;
using namespace LemonLib;
int main()
{
try
{
THROW_EXCEPTION(NoEnoughMemoryException, "hello, this is Exception test...");
}
catch (const NoEnoughMemoryException& e)
{
cout << "catch (const NoEnoughMemoryException& 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;
}