• 第十三课 类族结构的进化


      前几节我们开发的智能指针类和异常类族并没有继承自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的基础设施构建

        顶层父类

        智能指针

        异常类

  • 相关阅读:
    Day2-Python爬虫小练 爬取百科词条
    Day1-python轻量级爬虫
    大数据处理课堂测试1
    周记7-28
    周记7-21
    周记7-14
    软件工程课程总结
    进度15
    NABCD
    团队项目成员和题目
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9500889.html
Copyright © 2020-2023  润新知