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

Posted pylearn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构开发:学习前的准备(下)相关的知识,希望对你有一定的参考价值。

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. 异常类











以上是关于数据结构开发:学习前的准备(下)的主要内容,如果未能解决你的问题,请参考以下文章

从0开始学Java 第一期 开发前的准备

Spring Boot 2.x 入门前的准备-IntelliJ IDEA 开发工具的安装与使用

学习webpack前的准备工作

关于学习JAVA前的部分准备

node学习前的准备-node.js初级

项目开发前的准备工作