1. 遵循经典设计准则
(1)DTLib中所有类位于单一的继承树下
(2)改进的关键点
①Exception类继承自Object类:堆空间中创建异常对象失败时,返回NULL指针。
②新增InvalidOperationException类:成员函数调用时,如果状态不正确则抛出异常。
③SmartPointer类继承自Object类:堆空间中创建智能指针对象失败时,返回NULL指针。
2. DTLib的开发方式和注意事项
(1)迭代开发:每次完成一个小的目标,持续开发,最终打造可复用类库
(2)单一继承树:所有类都继承自Object,规范堆对象创建时的行为
(3)只抛异常,不处理异常:使用THROW_EXCEPTION抛出异常,提高可移植性。这样就可以比较方便地将代码移植到老的编译器,所要做的工作只需将THROW_EXCEPTION宏后半部分注释掉,即#define THROW_EXCEPTION(e, m) //(throw e(m, __FILE__, __LINE__)))。同时由于DTLib库只抛异常,而不处理异常,这意味着库中无需使用try-catch语句,因此就可以把异常相关的处理从DTLib中剔除,让使用库的人自己去处理异常,从而提高了代码的可移植性)
(4)弱耦合性:尽量不使用标准库中的类和函数,提高可移植性。
【编程实验】类族结构的进化
//Object.h
#ifndef _OBJECT_H_ #define _OBJECT_H_ namespace DTLib { class Object { public: //以下四个重载函数用于统一不同编译器new失败时的结果不同的问题。 //throw()表示不抛出异常,即如果申请内请失败时,统一返回NULL而不抛异常 void* operator new(unsigned int size) throw(); void operator delete(void* p); void* operator new[](unsigned int size) throw(); void operator delete[](void* p); virtual ~Object() = 0; }; } #endif // _OBJECT_H_
//Object.cpp
#include "Object.h" #include <cstdlib> #include <iostream> using namespace std; namespace DTLib { void * Object::operator new(unsigned int size) throw() { cout <<"Object::operator new: " << size << endl; return malloc(size); } void Object::operator delete(void *p) { cout <<"Object::operator delete: " << p << endl; free(p); } void *Object::operator new[](unsigned int size) throw() { //当用new Test[5]时,只须传入数组元素的个数,编译器会向operator new[](...)函数的参数 //传入5*sizeof(Test) + sizeof(unsigned int),其中的sizeof(unsigned int)为额外 //空间,用于保存元素的个数。 cout <<"Object::operator new[]: " << size << endl; return malloc(size); } void Object::operator delete[](void *p) { cout <<"Object::operator delete[]: " << p << endl; free(p); } Object::~Object() { } }
//SmartPointer.h
#ifndef _SMARTPOINTER_H_ #define _SMARTPOINTER_H_ #include "Object.h" namespace DTLib { //智能指针 template<typename T> class SmartPointer : public Object { T* m_pointer; public: //构造函数 SmartPointer(T* p = NULL) { m_pointer = p; } //拷贝构造函数 SmartPointer(const SmartPointer<T>& obj) { m_pointer = obj.m_pointer; //所有权转移,使得同一时刻只能由一个指针指向堆空间 const_cast<SmartPointer<T>&>(obj).m_pointer = NULL; } //重载赋值操作符 SmartPointer<T>& operator=(const SmartPointer<T>& obj) { if(this != &obj){ delete m_pointer; m_pointer = obj.m_pointer; //所有权转移 const_cast<SmartPointer<T>&>(obj).m_pointer = NULL; } return *this; } //重载->操作符 T* operator->() { return m_pointer; } //重载*操作符 T& operator*() { return *m_pointer; } bool isNull() { return (m_pointer == NULL); } T* get() { return m_pointer; } ~SmartPointer() { delete m_pointer; } }; } #endif // _SMARTPOINTER_H_
//Exception.h
#ifndef _EXCEPTION_H_ #define _EXCEPTION_H_ #include "Object.h" namespace DTLib { #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); virtual const char* message() const; virtual const char* location() const; //注意: //(1)析构函数是较为特殊的函数,一旦定义了析构函数,不管这个函数是不是纯虚函数,就 //必须提供实现。因为,对象在销毁时,最后都会调用父类的析构函数。如果父类不提供实现, //当对象销毁过程中调用到父类析构函数时,就找不到析构函数,也就不知该如何析构下去。 //因此,尽管这里将析构函数声明为纯虚函数,但Exception类仍提供析构函数的实现。以便 //最后正确释放掉m_message和m_location所指的堆空间. //(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 NotEnoughMemoryException: public Exception { public: NotEnoughMemoryException():Exception(0){} NotEnoughMemoryException(const char* message):Exception(message){} NotEnoughMemoryException(const char*file, int line):Exception(file, line){} NotEnoughMemoryException(const char *message, const char* file, int line):Exception(message, file, line){} NotEnoughMemoryException(const NotEnoughMemoryException& e): Exception(e){} NotEnoughMemoryException& operator=(const NotEnoughMemoryException& 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> using namespace std; namespace DTLib { void Exception::init(const char *message, const char *file, int line) { m_message = strdup(message); //复制message的内容 m_location = NULL; if(file != NULL){ char sl[16]={0}; itoa(line, sl, 10);//将整数line转为字符串,其中的10表示转换为十进制格式 //m_location的格式为:file:line ; m_location = static_cast<char*>(malloc(strlen(file) + strlen(sl) + 2)); //注意:申请内存失败时无须再抛NotEnoughMemoryException异常,从宏观上看,父类 //是无法抛出子类型的异常的。从逻辑上看也不能抛出这个异常,因为当父类构造时出现异常时, //如果去抛出子类异常,则必然需要构造子类,但这又得先调用父类构造函数(会再一次产 //生异常,从而造成Exception构造函数的递归调用,从而造成死循环!) if(m_location != NULL){ //内存申请成功 m_location = strcpy(m_location, file); m_location = strcat(m_location, ":"); m_location = strcat(m_location, sl); } } } //构造函数 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 "SmartPointer.h" #include "Exception.h" using namespace std; using namespace DTLib; int main() { SmartPointer<int>* sp = new SmartPointer<int>(); delete sp; InvalidOperationException* e = new InvalidOperationException(); delete e; return 0; } /*输出结果 Object::operator new: 8 Object::operator delete: 0x7a12a8 Object::operator new: 12 Object::operator delete: 0x7a12a8 */
3. 第一阶段学习总结
(1)数据结构与算法之间的关系
(2)算法效率的度量方法
(3)DTLib的基础设施构建:顶层父类、智能指针、异常类…