• 数据结构开发(2):学习前的准备(下)


    0.目录

    1.顶层父类的创建

    2.类族结构的进化

    3.小结

    参考前文传送门:
    C++解析(29):类型识别
    C++解析(31):自定义内存管理(完)
    C++解析-外传篇(1):异常处理深度解析
    C++解析-外传篇(2):函数的异常规格说明
    C++解析-外传篇(3):动态内存申请的结果

    1.顶层父类的创建

    当代软件架构实践中的经验:

    • 尽量使用单重继承的方式进行系统设计
    • 尽量保持系统中只存在单一的继承树
    • 尽量使用组合关系代替继承关系

    不幸的事实:

    • C++语言的灵活性使得代码中可以存在多个继承树
    • C++编译器的差异使得同样的代码可能表现不同的行为

    (编译器的差异:new操作如果失败会发生什么?

    创建 StLib::Object 类的意义:

    • 遵循经典设计准则,所有数据结构都继承自Object类
    • 定义动态内存申请的行为,提高代码的移植性

    顶层父类的接口定义:

    示例——顶层父类的创建:
    创建Object.h

    #ifndef OBJECT_H
    #define OBJECT_H
    
    namespace StLib
    {
    
    class Object
    {
    public:
        void* operator new (size_t size) throw();
        void operator delete (void* p);
        void* operator new[] (size_t 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 StLib
    {
    
    void* Object::operator new (size_t 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[] (size_t size) throw()
    {
        return malloc(size);
    }
    
    void Object::operator delete[] (void* p)
    {
        free(p);
    }
    
    Object::~Object()
    {
    
    }
    
    }
    

    main.cpp测试

    #include <iostream>
    #include "Object.h"
    
    using namespace std;
    using namespace StLib;
    
    class Test : public Object
    {
    public:
        int i;
        int j;
    };
    
    class Child : public Test
    {
    public:
        int k;
    };
    
    int main()
    {
        Object* obj1 = new Test();
        Object* obj2 = new Child();
    
        cout << "obj1 = " << obj1 << endl;
        cout << "obj2 = " << obj2 << endl;
        // ... ...
    
        delete obj1;
        delete obj2;
    
        return 0;
    }
    

    运行结果为:

    Object::operator new: 16
    Object::operator new: 24
    obj1 = 0000025D8EA46F00
    obj2 = 0000025D8EA42D50
    Object::operator delete: 0000025D8EA46F00
    Object::operator delete: 0000025D8EA42D50
    

    2.类族结构的进化

    遵循经典设计准则——StLib中的所有类位于单一的继承树

    改进的关键点:

    • Exception 类继承自 Object
      1. 堆空间中创建异常对象失败时,返回 NULL 指针
    • 新增 InvalidOperationException 异常类
      1. 成员函数调用时,如果状态不正确则抛出异常
    • SmartPointer 类继承自 Object
      1. 堆空间中创建智能指针对象失败时,返回 NULL 指针

    最终Object类:
    Object.h

    #ifndef OBJECT_H
    #define OBJECT_H
    
    namespace StLib
    {
    
    class Object
    {
    public:
        void* operator new (size_t size) throw();
        void operator delete (void* p);
        void* operator new[] (size_t 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 StLib
    {
    
    void* Object::operator new (size_t size) throw()
    {
        return malloc(size);
    }
    
    void Object::operator delete (void* p)
    {
        free(p);
    }
    
    void* Object::operator new[] (size_t size) throw()
    {
        return malloc(size);
    }
    
    void Object::operator delete[] (void* p)
    {
        free(p);
    }
    
    Object::~Object()
    {
    
    }
    
    }
    

    改进SmartPointer类:
    SmartPointer.h

    #ifndef SMARTPOINTER_H
    #define SMARTPOINTER_H
    
    #include "Object.h"
    
    namespace StLib
    {
    
    template <typename T>
    class SmartPointer : public Object
    {
    protected:
        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类:
    Exception.h

    #ifndef EXCEPTION_H
    #define EXCEPTION_H
    
    #include "Object.h"
    
    using namespace std;
    
    namespace StLib
    {
    
    // 使用宏简化代码
    #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 NullPointerException& e) : Exception(e) { }
        IndexOutOfBoundsException& operator= (const NullPointerException& 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 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>
    
    namespace StLib
    {
    
    void Exception::init(const char* message, const char* file, int line)
    {
        /* message指向的字符串有可能在栈上,有可能在堆空间,还有可能在全局数据区
         * strdup()将字符串复制一份到堆空间中
         * file:发生异常的文件名
         * line:发生异常的行号
         * m_location的长度加2,一个给":",一个给""
         */
        m_message = strdup(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 = strcpy(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);
    }
    
    }
    

    StLib 的开发方式注意事项

    • 迭代开发
      1. 每次完成一个小的目标,持续开发,最终打造可复用类库
    • 单一继承树
      1. 所有类都继承自Object,规范堆对象创建时的行为
    • 只抛异常,不处理异常
      1. 使用 THROW_ EXCEPTION 抛出异常,提高可移植性
    • 弱耦合性
      1. 尽量不使用标准库中的类和函数,提高可移植性

    3.小结

    • Object类是StLib中数据结构类的顶层父类
    • Object类用于统一动态内存申请的行为
    • 在堆中创建Object子类的对象,失败时返回NULL
    • Object类为纯虚父类,所有子类都能进行动态类型识别

    第一阶段学习总结:

    • 数据结构算法之间的关系
    • 算法效率的度量方法
    • StLib的基础设施构建
      1. 顶层父类
      2. 智能指针
      3. 异常类
  • 相关阅读:
    突袭HTML5之HTML元素扩展(上) 新增加的元素
    DIV常见任务(下) 变身为编辑器
    突袭HTML5之Javascript API扩展3 本地存储
    突袭HTML5之Javascript API扩展5 其他扩展
    DIV常见任务(上) 常规任务
    突袭HTML5之HTML元素扩展(下) 增强的Form元素
    突袭HTML5之WebGL 3D概述(下) 借助类库开发
    突袭HTML5之Javascript API扩展4 拖拽
    突袭HTML5之Javascript API扩展1 Web Worker异步执行
    突袭HTML5之Javascript API扩展2 地理信息服务
  • 原文地址:https://www.cnblogs.com/PyLearn/p/10109785.html
Copyright © 2020-2023  润新知