1,数据结构库架构图(本文暂时架构图,后有更改):
2,依赖异常类创建的库稳定性很好;
3,异常类型可以是自定义类类型:
1,对于类类型异常的匹配依旧是至上而下严格匹配;
2,赋值兼容性原则在异常匹配中依然适用;
3,一般而言:
1,匹配子类异常的 catch 放在上部;
2,匹配父类异常的 catch 放在下部;
4,纯虚的析构函数仅仅用来说明当前的类是抽象类,其它没有任何说明了;
5,纯虚析构函数的实现:
1,C++ 中规定纯虚函数不需要提供实现,等着子类实现;
2,C++ 中规定,只要定义了析构函数,不管其是否为纯虚函数,一定要提供实现,因为在实现一个析构函数的时候,最后肯定要调用父类的析构函数,如果父类的析构函数是纯虚函数,并且这个纯虚函数没有具体实现,则调用到顶层父类的析构函数时没有实现,则更加奇怪,所以 C++ 语言规定了这个原则;
6,现代 C++ 库必然包含必要的异常类族,异常类是数据结构类所依赖的“基础设施”,其成员关系为:
7,异常类功能定义:
8,异常类中的接口定义:
9,异常类族创建:
1,Exception.h 的创建:
1 #ifndef EXCEPTION_H 2 #define EXCEPTION_H 3 4 #include "Object.h" 5 6 namespace DTLib 7 { 8 9 #define THROW_EXCEPTION(e, m) (throw e(m, __FILE__, __LINE__)) //直接抛出异常对象,具体文件名和行号宏自己写出;当不能够用异常处理机制的时候,只需用在这里注释掉就可以了 10 11 class Exception : public Object // 设计为顶层的抽象类,没有对象,只能继承; 12 { 13 protected: 14 char* m_message; 15 char* m_location; 16 void init(const char* message, const char* file, int line); 17 18 public: 19 Exception(const char* message); 20 Exception(const char* file, int line); 21 Exception(const char* message, const char* file, int line); 22 Exception(const Exception& e); 23 Exception& operator= (const Exception& e); 24 25 virtual const char* message() const; // 详细的异常说明信息; 26 virtual const char* location() const; // 定位异常位置信息; 27 virtual ~Exception() = 0; //抽象类,析构函数用虚函数;纯虚函数的实现等着子类来完成;但凡定义析构函数,必须实现,因为析构函数时,必须要调用父类的析构函数。 28 }; 29 30 class ArithmeticException : public Exception 31 { 32 public: 33 ArithmeticException() : Exception(0){} 34 ArithmeticException(const char* message) : Exception(message){} 35 ArithmeticException(const char *file, int line) : Exception(file, line){} 36 ArithmeticException(const char* message, const char* file, int line) : Exception(message, file, line){} 37 ArithmeticException(const ArithmeticException& e) : Exception(e) {} 38 ArithmeticException& operator =(const ArithmeticException& e) 39 { 40 Exception::operator =(e); 41 42 return *this; 43 } 44 }; 45 46 class NullPointerException : public Exception 47 { 48 public: 49 NullPointerException() : Exception(0){} 50 NullPointerException(const char* message) : Exception(message){} 51 NullPointerException(const char *file, int line) : Exception(file, line){} 52 NullPointerException(const char* message, const char* file, int line) : Exception(message, file, line){} 53 NullPointerException(const NullPointerException& e) : Exception(e) {} 54 NullPointerException& operator =(const NullPointerException& e) 55 { 56 Exception::operator =(e); 57 58 return *this; 59 } 60 }; 61 62 class IndexOutOfBoundsException : public Exception 63 { 64 public: 65 IndexOutOfBoundsException() : Exception(0){} 66 IndexOutOfBoundsException(const char* message) : Exception(message){} 67 IndexOutOfBoundsException(const char *file, int line) : Exception(file, line){} 68 IndexOutOfBoundsException(const char* message, const char* file, int line) : Exception(message, file, line){} 69 IndexOutOfBoundsException(const IndexOutOfBoundsException& e) : Exception(e) {} 70 IndexOutOfBoundsException& operator =(const IndexOutOfBoundsException& e) 71 { 72 Exception::operator =(e); 73 74 return *this; 75 } 76 }; 77 78 class NoEnoughMemoryException : public Exception 79 { 80 public: 81 NoEnoughMemoryException() : Exception(0){} 82 NoEnoughMemoryException(const char* message) : Exception(message){} 83 NoEnoughMemoryException(const char *file, int line) : Exception(file, line){} 84 NoEnoughMemoryException(const char* message, const char* file, int line) : Exception(message, file, line){} 85 NoEnoughMemoryException(const NoEnoughMemoryException& e) : Exception(e) {} 86 NoEnoughMemoryException& operator =(const NoEnoughMemoryException& e) 87 { 88 Exception::operator =(e); 89 90 return *this; 91 } 92 }; 93 94 class InvalidParameterException : public Exception 95 { 96 public: 97 InvalidParameterException() : Exception(0){} 98 InvalidParameterException(const char* message) : Exception(message){} 99 InvalidParameterException(const char *file, int line) : Exception(file, line){} 100 InvalidParameterException(const char* message, const char* file, int line) : Exception(message, file, line){} 101 InvalidParameterException(const InvalidParameterException& e) : Exception(e) {} 102 InvalidParameterException& operator =(const InvalidParameterException& e) 103 { 104 Exception::operator =(e); 105 106 return *this; 107 } 108 }; 109 110 class InvalidOperationException : public Exception 111 { 112 public: 113 InvalidOperationException() : Exception(0){} 114 InvalidOperationException(const char* message) : Exception(message){} 115 InvalidOperationException(const char *file, int line) : Exception(file, line){} 116 InvalidOperationException(const char* message, const char* file, int line) : Exception(message, file, line){} 117 InvalidOperationException(const InvalidOperationException& e) : Exception(e) {} 118 InvalidOperationException& operator =(const InvalidOperationException& e) 119 { 120 Exception::operator =(e); 121 122 return *this; 123 } 124 }; 125 126 } 127 128 #endif // EXCEPTION_H
2,Exception.cpp的创建:
1 #include "Exception.h" 2 #include <cstring> 3 #include <cstdlib> 4 5 using namespace std; 6 7 namespace DTLib 8 { 9 10 void Exception::init(const char* message, const char* file, int line) 11 { 12 m_message = (message ? strdup(message) : NULL); // 将message复制一份指向堆空间,而内容相同;保证是独立的堆空间;采用三目运算符因为 message 可能为空但是 strdup 没有判断为空的情况; 13 14 if( file != NULL) 15 { 16 char sl[16] = {0}; 17 18 itoa(line, sl, 10); //这里不懂 19 20 m_location = static_cast<char*>(malloc(strlen(file) + strlen(sl) + 2)); // 加上冒号和结束符; 21 22 if( m_location != NULL ) // 对于 DTLib 里面的类的话,动态申请后一定要判断是否为空指针,这里不再做为空的异常处理,免得陷入死循环 23 { 24 m_location = strcpy(m_location, file); 25 m_location = strcat(m_location, ":"); 26 m_location = strcat(m_location, sl); 27 } 28 } 29 else 30 { 31 m_location = NULL; // 这里已经做了 m_location 为空的准备; 32 } 33 } 34 35 Exception::Exception(const char* message) 36 { 37 init(message, NULL, 0); 38 } 39 40 Exception::Exception(const char* file, int line) 41 { 42 init(NULL, file, line); 43 } 44 45 Exception::Exception(const char* message, const char* file, int line) 46 { 47 init(message, file, line); 48 } 49 50 Exception::Exception(const Exception& e) //深拷贝,必须实现 51 { 52 m_message = strdup(e.m_message); // 保证是独立的堆空间; 53 m_location = strdup(e.m_location); 54 } 55 56 Exception& Exception::operator= (const Exception& e)//深拷贝,必须实现 57 { 58 if( this != &e) 59 { 60 free(m_message); 61 free(m_location); 62 63 m_message = strdup(e.m_message); // 保证是独立的堆空间; 64 m_location = strdup(e.m_location); 65 } 66 67 return *this; 68 } 69 70 const char* Exception::message() const 71 { 72 return m_message; 73 } 74 75 const char* Exception::location() const 76 { 77 return m_location; 78 } 79 80 Exception::~Exception() 81 { 82 free(m_message); 83 free(m_location); 84 }
10,设计原则:
1,在可复用代码库设计时,尽量使用面相对象技术进行架构;
2,尽量使用异常处理机制分离正常逻辑和异常逻辑;
11,小结:
1,现代 C++ 库必然包含必要的异常类族;
2,所有库中的数据结构都依赖于异常机制;
3,异常机制能够分离库中代码的正常逻辑和异常逻辑;