前几节我们开发的智能指针类和异常类族并没有继承自Object,现在我们需要将它们进行整合,作为DTLib这个类库的基础设施。整合的时候需要遵循现代软件的架构模式。

  遵循经典设计准则

    DTLib中所有类位于单一继承树,可以根据下图中的方式进行整合:

 

  在异常类族中有了新的成员InvalidOperationException异常类。为什么要增加这个异常类呢?因为我们创建的数据结构类是有状态的,在不同状态下,成员函数调用的行为是不同的。特别的在某些类对象的初识状态下,某些成员函数是不能调用的,如果硬是要调用这些函数,就会抛出这个非法操作的异常。

改进的关键点:

  Exception类继承自Object类

    堆空间中创建异常对象失败时,返回NULL指针

  新增InvalidOperationException异常类

    成员函数调用时,如果状态不正确则抛出异常

  SmartPointer类继承自Object类

    堆空间中创建智能指针对象失败时,返回NULL指针

DTLib中类的使用原则:

  如果在堆空间中创建DTLib库中的对象,创建完之后要判断一下是否返回了一个合法的指针。因为创建失败时是不会返回异常的。

 改造后的程序库如下:

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 
 17     void init(const char* message, const char* file, int line);
 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 
 23     Exception(const Exception& e);
 24     Exception& operator= (const Exception& e);
 25 
 26     virtual const char* message() const;
 27     virtual const char* location() const;
 28 
 29     virtual ~Exception() = 0;
 30 };
 31 
 32 class ArithmeticException : public Exception
 33 {
 34 public:
 35     ArithmeticException() : Exception(0, 0, 0) {}
 36     ArithmeticException(const char* message) : Exception(message) {}
 37     ArithmeticException(const char* file, int line) : Exception(file, line) {}
 38     ArithmeticException(const char* message, const char* file, int line) : Exception(message, file, line){}
 39 
 40     ArithmeticException(const ArithmeticException& e) : Exception(e) {}
 41 
 42     ArithmeticException& operator=(const ArithmeticException& e)
 43     {
 44         Exception::operator =(e);
 45 
 46         return *this;
 47     }
 48 };
 49 
 50 class NullPointerException : public Exception
 51 {
 52 public:
 53     NullPointerException() : Exception(0, 0, 0) {}
 54     NullPointerException(const char* message) : Exception(message) {}
 55     NullPointerException(const char* file, int line) : Exception(file, line) {}
 56     NullPointerException(const char* message, const char* file, int line) : Exception(message, file, line){}
 57 
 58     NullPointerException(const NullPointerException& e) : Exception(e) {}
 59 
 60     NullPointerException& operator=(const NullPointerException& e)
 61     {
 62         Exception::operator =(e);
 63 
 64         return *this;
 65     }
 66 };
 67 
 68 class IndexOutOfBoundsException : public Exception
 69 {
 70 public:
 71     IndexOutOfBoundsException() : Exception(0, 0, 0) {}
 72     IndexOutOfBoundsException(const char* message) : Exception(message) {}
 73     IndexOutOfBoundsException(const char* file, int line) : Exception(file, line) {}
 74     IndexOutOfBoundsException(const char* message, const char* file, int line) : Exception(message, file, line){}
 75 
 76     IndexOutOfBoundsException(const IndexOutOfBoundsException& e) : Exception(e) {}
 77 
 78     IndexOutOfBoundsException& operator=(const IndexOutOfBoundsException& e)
 79     {
 80         Exception::operator =(e);
 81 
 82         return *this;
 83     }
 84 };
 85 
 86 class NoEnoughMemoryException : public Exception
 87 {
 88 public:
 89     NoEnoughMemoryException() : Exception(0, 0, 0) {}
 90     NoEnoughMemoryException(const char* message) : Exception(message) {}
 91     NoEnoughMemoryException(const char* file, int line) : Exception(file, line) {}
 92     NoEnoughMemoryException(const char* message, const char* file, int line) : Exception(message, file, line){}
 93 
 94     NoEnoughMemoryException(const NoEnoughMemoryException& e) : Exception(e) {}
 95 
 96     NoEnoughMemoryException& operator=(const NoEnoughMemoryException& e)
 97     {
 98         Exception::operator =(e);
 99 
100         return *this;
101     }
102 };
103 
104 class InvalidParameterException : public Exception
105 {
106 public:
107     InvalidParameterException() : Exception(0, 0, 0) {}
108     InvalidParameterException(const char* message) : Exception(message) {}
109     InvalidParameterException(const char* file, int line) : Exception(file, line) {}
110     InvalidParameterException(const char* message, const char* file, int line) : Exception(message, file, line){}
111 
112     InvalidParameterException(const InvalidParameterException& e) : Exception(e) {}
113 
114     InvalidParameterException& operator=(const InvalidParameterException& e)
115     {
116         Exception::operator =(e);
117 
118         return *this;
119     }
120 };
121 
122 class InvalidOperationException : public Exception
123 {
124 public:
125     InvalidOperationException() : Exception(0, 0, 0) {}
126     InvalidOperationException(const char* message) : Exception(message) {}
127     InvalidOperationException(const char* file, int line) : Exception(file, line) {}
128     InvalidOperationException(const char* message, const char* file, int line) : Exception(message, file, line){}
129 
130     InvalidOperationException(const InvalidOperationException& e) : Exception(e) {}
131 
132     InvalidOperationException& operator=(const InvalidOperationException& e)
133     {
134         Exception::operator =(e);
135 
136         return *this;
137     }
138 };
139 
140 }
141 
142 #endif // EXCEPTION_H

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 = strdup(message);
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)
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;
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_message = 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 }
85 
86 }

第22行的init函数中我们加入了空指针的判断,当malloc申请不成功时,也即m_location为空时,我们什么也不做,就让m_location为空。如果m_location为空,我们抛出异常,会造成死循环,因为在init函数中,我们的Exception对象还没有构造好呢。

SmartPointer.h

 1 #ifndef SMARTPOINTER_H
 2 #define SMARTPOINTER_H
 3 
 4 #include "Object.h"
 5 
 6 namespace DTLib
 7 {
 8 
 9 template <typename T>
10 class SmartPointer : public Object
11 {
12 protected:
13     T *m_pointer;
14 
15 public:
16     SmartPointer(T *p = NULL)
17     {
18         m_pointer = p;
19     }
20 
21     SmartPointer(const SmartPointer<T>& obj)
22     {
23         m_pointer = obj.m_pointer;
24 
25         const_cast<SmartPointer<T>&>(obj).m_pointer = NULL;
26     }
27 
28     SmartPointer<T>& operator= (const SmartPointer<T>& obj)
29     {
30         if(this != &obj)
31         {
32             delete m_pointer;
33 
34             m_pointer = obj.m_pointer;
35 
36             const_cast<SmartPointer<T>&>(obj).m_pointer = NULL;
37         }
38 
39         return *this;
40     }
41 
42     T* operator-> ()
43     {
44         return m_pointer;
45     }
46 
47     T& operator* ()
48     {
49         return *m_pointer;
50     }
51 
52     bool isNull()
53     {
54         return (m_pointer == NULL);
55     }
56 
57     T* get()
58     {
59         return m_pointer;
60     }
61 
62     ~SmartPointer()
63     {
64         delete m_pointer;
65     }
66 };
67 
68 }
69 
70 #endif // SMARTPOINTER_H

main函数测试程序如下:

 1 #include <iostream>
 2 #include "Exception.h"
 3 #include "Object.h"
 4 #include "SmartPointer.h"
 5 using namespace std;
 6 using namespace DTLib;
 7 
 8 
 9 
10 int main()
11 {
12     SmartPointer<int> *sp = new SmartPointer<int>();
13 
14     delete sp;
15 
16     return 0;
17 }

我们在Exception.cpp中new和delete重载的地方打上断点,执行程序结果如下:

   

可以看到,程序最终执行到了我们自己定义的new和delete处。

 DTLib的开发方式和注意事项:

迭代开发:

  每次完成一个小的目标,持续开发,最终打造一个可复用类库

单一继承树:

  所有类都继承自Object,规范堆对象创建时的行为

只抛异常,不处理异常:

  使用THROW_EXCEPTION抛出异常,提高可移植性,有些老的编译器不支持异常,不支持try...catch...,或者有的公司规定不能使用异常机制,这时,如果还想使用

  这个库,我们只需将这个宏定义为空

弱耦合性:

  尽量不使用标准库中的类和函数,提高可移植性

 第一阶段的总结:

  数据结构与算法之间的关系

  算法效率的度量方法

  DTLib的基础设施构建

    顶层父类

    智能指针

    异常类

 

posted on 2018-08-19 12:15  周伯通789  阅读(219)  评论(0编辑  收藏  举报