遵循经典设计准则

  • DTLib 中的所有类位于单一的继承树

image.png

改进的关键点

  • Exception 类继承自 Object

    • 堆空间中创建异常对象失败时,返回NULL指针
  • 新增 InvalidOperationException 异常类

    • 成员函数调用时,如果状态不正确则抛出异常
  • SmartPointer 类继承自 Object 类

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

编程实验:类族结构的进化

文件:SmartPointer.h

#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H

#include "Object.h"

namespace DTLib
{

template<typename T>
class SmartPointer : public Object  // 修改
{
public:
    SmartPointer(T *p = nullptr)
    {
        m_pointer = p;
    }

    SmartPointer(const SmartPointer &obj)
    {
        m_pointer = obj.m_pointer;
        const_cast<SmartPointer&>(obj).m_pointer = nullptr;
    }

    SmartPointer &operator= (const SmartPointer &obj)
    {
        if (this != &obj)
        {
            delete m_pointer;
            m_pointer = obj.m_pointer;
            const_cast<SmartPointer&>(obj).m_pointer = nullptr;
        }

        return *this;
    }

    T *operator-> ()
    {
        return m_pointer;
    }

    T &operator* ()
    {
        return *m_pointer;
    }

    bool isNull()
    {
        return (m_pointer == nullptr);
    }

    T *get()
    {
        return m_pointer;
    }

    ~SmartPointer()
    {
        delete m_pointer;
    }

protected:
    T *m_pointer = nullptr;
};

}

#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  // 修改
{
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;

protected:
    char *m_message = nullptr;
    char *m_location = nullptr;
};

class ArithmeticExcption : public Exception
{
public:
    ArithmeticExcption() : Exception(nullptr) { }
    ArithmeticExcption(const char *message) : Exception(message) { }
    ArithmeticExcption(const char *file, int line) : Exception(file, line) { }
    ArithmeticExcption(const char *message, const char *file, int line) : Exception(message, file, line) { }

    ArithmeticExcption(const ArithmeticExcption &e) : Exception(e) { }

    ArithmeticExcption &operator= (const ArithmeticExcption &e)
    {
        Exception::operator=(e);

        return *this;
    }
    ~ArithmeticExcption() override { }
};

class NullPointerException : public Exception
{
public:
    NullPointerException() : Exception(nullptr) { }
    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;
    }
    ~NullPointerException() override { }
};

class IndexOutOfBoundsException : public Exception
{
public:
    IndexOutOfBoundsException() : Exception(nullptr) { }
    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;
    }
    ~IndexOutOfBoundsException() override { }
};

class NoEnoughMemoryException : public Exception
{
public:
    NoEnoughMemoryException() : Exception(nullptr) { }
    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;
    }
    ~NoEnoughMemoryException() override { }
};

class InvalidParameterExcetion : public Exception
{
public:
    InvalidParameterExcetion() : Exception(nullptr) { }
    InvalidParameterExcetion(const char *message) : Exception(message) { }
    InvalidParameterExcetion(const char *file, int line) : Exception(file, line) { }
    InvalidParameterExcetion(const char *message, const char *file, int line) : Exception(message, file, line) { }

    InvalidParameterExcetion(const InvalidParameterExcetion &e) : Exception(e) { }

    InvalidParameterExcetion &operator= (const InvalidParameterExcetion &e)
    {
        Exception::operator=(e);

        return *this;
    }
    ~InvalidParameterExcetion() override { }
};

class InvalidOpertionExcetion : public Exception  // 增加
{
public:
    InvalidOpertionExcetion() : Exception(nullptr) { }
    InvalidOpertionExcetion(const char *message) : Exception(message) { }
    InvalidOpertionExcetion(const char *file, int line) : Exception(file, line) { }
    InvalidOpertionExcetion(const char *message, const char *file, int line) : Exception(message, file, line) { }

    InvalidOpertionExcetion(const InvalidOpertionExcetion &e) : Exception(e) { }

    InvalidOpertionExcetion &operator= (const InvalidOpertionExcetion &e)
    {
        Exception::operator=(e);

        return *this;
    }
    ~InvalidOpertionExcetion() override { }
};

}

#endif // EXCEPTION_H

文件:Exception.cpp (未修改)

#include "Exception.h"

#include <cstring>
#include <cstdlib>

namespace DTLib
{

Exception::Exception(const char *message) : Exception(message, nullptr, 0)
{
}

Exception::Exception(const char *file, int line) : Exception(nullptr, file, line)
{
}

Exception::Exception(const char *message, const char *file, int line)
{
    m_message = strdup(message);

    if (file != nullptr)
    {
        char sl[16] = {0};

        itoa(line, sl, 10);

        m_location = static_cast<char*>(malloc(strlen(file) + strlen(sl) + 2));
        m_location = strcpy(m_location, file);
        m_location = strcat(m_location, ":");
        m_location = strcat(m_location, sl);
    }
    else
    {
        m_location = nullptr;
    }
}

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()
{
    delete m_message;
    delete m_location;
}

}
  • DTLib 的开发方式和注意事项

    • 迭代开发

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

      • 所有类都继承自 Object,规范堆对象创建时的行为
    • 只抛异常,不处理异常

      • 使用 THROW_EXCEPTION 抛出异常,提高可移植性
    • 弱耦合性

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

说明1:只抛异常,不处理异常
背景:有公司会明确规定不允许使用异常处理机制(throw,try,catch)
解决方案:

#define THROW_EXCEPTION(e, m) //(throw e(m, __FILE__, __LINE__))

说明2:尽量不使用标准库中的内容
背景:有公司会明确规定不允许使用标准库
解决方案:当前只在Object文件和Exception文件中使用了malloc,free, strlen, strdup等极少数库函数,这是极其容易被替换的。

第一阶段学习总结

  • 数据结构与算法之间的关系
  • 算法效率的度量方法
  • DTLib 的基础设施构建

    • 顶层父类
    • 智能指针
    • 异常类

以上内容整理于狄泰软件学院系列课程,请大家保护原创!


TianSong
737 声望139 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧