首页 > 代码库 > 第十三课、类族的结构进化-------------------狄泰软件学院
第十三课、类族的结构进化-------------------狄泰软件学院
一、遵循经典设计原则
DTLib中的所有类位于单一继承树
IvalidOperationEXception是新增的异常类,描述某些成员函数在状态不对的时候被抛出
二、改进的关键点
1、EXception类继承自Object类:堆空间中创建异常对象失败时,返回NULL指针,用的是自己的new版本
更改:
2、新增IvalidOperationEXception异常类:成员函数调用时,如果状态不正确则抛出该异常
增加:
//非法操作异常 class IvalidOperationEXception:public Exception { public: IvalidOperationEXception():Exception(0) {} IvalidOperationEXception(const char* message):Exception(message) {} IvalidOperationEXception(const char* file, int line):Exception(file, line) {} IvalidOperationEXception(const char* message, const char* file, int line):Exception(message, file, line) {} IvalidOperationEXception(const IvalidOperationEXception& e): Exception(e) {} IvalidOperationEXception& operator = (const IvalidOperationEXception& e) { Exception::operator =(e); return *this; } };
3、SmartPointer类继承自Object类:堆空间中创建智能指针对象失败时,返回NULL指针
更改:
注:前面课程的代码还有一些不完美
在EXception.cpp中修改init()函数,判断申请内存是否成功
void Exception::init(const char* message, const char* file, int line) { m_message = strdup(message);//指向的message可能在栈空间,也可能在堆空间或者全局数据去, //为了安全,这里先复制一份到堆空间 if( file != NULL) { char sl[16] = {0}; itoa(line, sl, 10);//首先将行号转化为字符串 m_location = static_cast<char*>(malloc(strlen(file) + strlen(sl) + 2)); if( m_location !=NULL ) { m_location = strcat(m_location, file); m_location = strcat(m_location, ":"); m_location = strcat(m_location, sl); } } else { m_location = NULL; } }
但是一定要注意判断语句的else分支中不能抛出内存不足的异常,原因可以从下面两个方面分析
(1)、站在一个高的角度看,内存不足的异常类是继承自抽象的异常父类,老爸还没存生就抛出儿子肯定是非法的
(2)、站在代码的角度看,构建对象的会先调用父类的构造函数,肯定又会进入到init()函数,最终会造成死循环
所以说最好的办法就是省去else语句。
三、第一阶段完整代码
#ifndef OBJECT_H #define OBJECT_H namespace DTLib { class Object { public: 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
#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() { cout << "Object::operator new[]" << endl; return malloc(size); } void Object::operator delete[] (void* p) { cout << "Object::operator delete[]" << endl; free(p); } Object::~Object() { } }
#ifndef SMARTPOINTER_H #define SMARTPOINTER_H #include "Object.h" namespace DTLib { template <typename T> class SmartPoiter : public Object { protected: T* m_pointer; public: SmartPoiter(T* p = NULL) { m_pointer = p; } SmartPoiter(const SmartPoiter<T>& obj) { m_pointer = obj.m_pointer; const_cast<SmartPoiter<T>&>(obj).m_pointer = NULL; } SmartPoiter<T>& operator = (const SmartPoiter<T>& obj) { if( this != &obj ) { delete m_pointer; m_pointer = obj.m_pointer; const_cast<SmartPoiter<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; } ~SmartPoiter() { delete m_pointer; } }; } #endif // SMARTPOINTER_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; 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 IvalidOperationEXception:public Exception { public: IvalidOperationEXception():Exception(0) {} IvalidOperationEXception(const char* message):Exception(message) {} IvalidOperationEXception(const char* file, int line):Exception(file, line) {} IvalidOperationEXception(const char* message, const char* file, int line):Exception(message, file, line) {} IvalidOperationEXception(const IvalidOperationEXception& e): Exception(e) {} IvalidOperationEXception& operator = (const IvalidOperationEXception& e) { Exception::operator =(e); return *this; } }; } #endif // EXCEPTION_H
#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可能在栈空间,也可能在堆空间或者全局数据去, //为了安全,这里先复制一份到堆空间 if( file != NULL) { char sl[16] = {0}; itoa(line, sl, 10);//首先将行号转化为字符串 m_location = static_cast<char*>(malloc(strlen(file) + strlen(sl) + 2)); if( m_location !=NULL ) { m_location = strcat(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); } }
#include <iostream> #include "Object.h" #include "Exception.h" #include "SmartPointer.h" using namespace std; using namespace DTLib; int main() { IvalidOperationEXception* p = new IvalidOperationEXception(); delete p; SmartPoiter<int>* s = new SmartPoiter<int>(); delete s; return 0; }
四、DTLib的开发方式和注意事项
1、迭代开发:每次完成一个小目标,持续开发,最终打造可复用类库
2、单一继承树:所有类都继承自Object,规范堆空间创建时的行为
3、只抛异常,不处理异常:使用THROW_EXCEPTION抛出的异常,提高可移植性
4、若耦合性:尽量不使用标准库中的类和函数,提高可移植性
注:在一些老编译器中,可能不支持异常处理,我们可以将宏
#define THROW_EXCEPTION(e,m) (throw e(m, __FILE__, __LINE__))
修改为
#define THROW_EXCEPTION(e,m) //(throw e(m, __FILE__, __LINE__))
这样,抛出异常的语句就形同虚设了,相当于没有抛出一样,增加了可移植性。
五、第一阶段学习总结
1、数据结构与算法之间的关系
2、算法效率的度量方法
3、DTLib的基础设施
(1)、顶层父类
(2)、智能指针
(3)、异常类
第十三课、类族的结构进化-------------------狄泰软件学院