千家信息网

顶层父类的构建(五)

发表于:2025-12-03 作者:千家信息网编辑
千家信息网最后更新 2025年12月03日,在当代的软件架构实践中,我们有三条准则:1、尽量使用单重继承的方式进行系统设计;2、尽量保持系统中只存在单一的继承树;3、尽量使用组合关系代替继承关系。但是由于 C++ 语言的灵活性使得代码中可以存在
千家信息网最后更新 2025年12月03日顶层父类的构建(五)

在当代的软件架构实践中,我们有三条准则:1、尽量使用单重继承的方式进行系统设计;2、尽量保持系统中只存在单一的继承树;3、尽量使用组合关系代替继承关系。但是由于 C++ 语言的灵活性使得代码中可以存在多个继承树,C++ 编译器的差异使得同样的代码可能表现不同的行为。

我们想下,new 操作如果失败将会发生什么呢?那么肯定会导致异常嘛,这时我们便用到了前面构建的异常类,此时我们只需抛出一个内存不足的异常,便会得到一个提示。我们这时便有必要来创建一个顶层的父类了,那么创建它的意义在哪呢?一是遵循经典设计准则,所有的数据结构都继承自 Object 类,二是定义动态内存申请的行为,提高代码的移植性。下面我们来看看顶层父类的接口定义,如下所示

class Object{public:    void* operator new (unsigned int size) throw();    void operator delete (void* p);    void* operator new[] (unigned int size) throw();    void operator delete[] (void* p);    virtual ~Object() = 0;};

下来我们还是以代码为例来进行实验


Object.h 源码

#ifndef OBJECT_H#define OBJECT_Hnamespace DTLib{class Object{public:    void* operator new (unsigned int size) throw();    void operator delete (void* p);    void* operator new[] (unsigned int size) throw();    void operator delete[] (void* p);    virtual ~Object() = 0;};}#endif // OBJECT_H


Object.cpp 源码

#include "Object.h"#include #include using namespace std;namespace DTLib{void* Object::operator new (unsigned int 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[] (unsigned int size) throw(){    return malloc(sizeof(size));}void Object::operator delete[] (void* p){    free(p);}Object::~Object(){}}


main.cpp 源码

#include #include "Object.h"using namespace std;using namespace DTLib;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;}

我们来看看编译后的结果

我们看到在 main 函数中我们用 Object 父类的指针来创建了一个 Test 子类对象和 Child 子类对象。并且在创建对象的时候打印了 Object::operator new ,这很明显就是调用了我们自己指定的 malloc 方式。为什么 Test 对象打印的是 12 呢?因为它里面包含了两个 public 成员变量(int),再加上一个指向虚函数表的指针,一共是 12 个字节。底下的 Child 子类的分析是一样的。在析构的时候我们看到析构时也打印出了我们写的 Object::operator delete ,由此可以看出它的析构也是调用的是我们自己定义的。

下来我们来看看经典设计准则是怎样的,如下,我们自己的 DTLib 中华的所有类是位于单一的继承树的

我们再基于上面创建的顶层父类来改善下我们之前写的异常类和智能指针(在 C++ 中有介绍过)。

1、Exception 类继承自 Object 类。即堆空间中创建异常对象失败时返回 NULL 指针

2、新增 InvalidOperationException 异常类。在成员函数调用时,如果状态不正常则抛出异常类

3、SmartPointer 类继承自 Object 类。在堆空间中创建智能指针对象失败时返回 NULL 指针

下来我们还是以代码为例来进行说明


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{private:    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();};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 IndexOutOfBoundsException& e) : Exception(e) {}    IndexOutOfBoundsException& operator= (const IndexOutOfBoundsException& 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 InvalidParameterException& e)    {        Exception::operator =(e);        return *this;    }};}#endif // EXCEPTION_H



Exception.cpp 源码

#include "Exception.h"#include #include using namespace std;namespace DTLib{void Exception::init(const char* message, const char* file, int line){    m_message = (message ? strdup(message) : NULL);    if( file != NULL )    {        char s1[16] = {0};        itoa(line, s1, 10);        m_location = static_cast(malloc(strlen(file) + strlen(s1) + 2));        m_location = strcpy(m_location, file);        m_location = strcat(m_location, ":");        m_location = strcat(m_location, s1);    }    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 = e.m_message;    m_location = e.m_location;}Exception& Exception::operator= (const Exception& e){    if( this != &e )    {        free(m_message);        free(m_location);        m_message = e.m_message;        m_location = 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);}}


SmartPointer.h 源码

#ifndef SMARTPOINTER_H#define SMARTPOINTER_H#include "Object.h"namespace DTLib{template < typename T >class SmartPointer : public Object{private:    T* m_pointer;public:    SmartPointer(T* p = NULL)    {        m_pointer = p;    }    SmartPointer(const SmartPointer& obj)    {        m_pointer = obj.m_pointer;        const_cast&>(obj).m_pointer = NULL;    }    SmartPointer& operator= (const SmartPointer& obj)    {        if( this != &obj )        {            delete m_pointer;            m_pointer = obj.m_pointer;            const_cast&>(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


main.cpp 源码

#include #include "SmartPointer.h"#include "Exception.h"using namespace std;using namespace DTLib;int main(){    SmartPointer* p = new SmartPointer();    delete p;    INvalidOPerationException* e = new INvalidOPerationException();    delete e;    return 0;}

我们在 Object 顶层父类中的 new 和 delete 函数中搭上断点,同时也在 main 函数中的 SmartPointerINvalidOPerationException 的 new 和 delete 操作中打上断点,看看程序的执行流,如下

第一幅图是执行 SmartPointer 指针的 new 和 delete 操作时输出的信息,第二幅图是执行 INvalidOPerationException 指针的 new 和 delete 操作时输出的信息。我们可以看到调用的 new 和 delete 操作都是 Object 中的函数。也就是说,我们现在的所有操作都是基于 Object 顶层父类的,由它统一 new 和 delete 的行为操作。我哦们在进行 DTLib 库的开发时需要注意:1、迭代 开发:也就是每次完成一个小目标,持续开发,最终打造可复用类库;2、单一继承树:所有树都继承自 Object,规范堆对象创建时的行为;3、只抛异常,不处理异常:使用 THROW_EXCEPTION 抛出异常,提高可移植性;4、弱耦合性:尽量不适应标准库中的类和函数,提高可移植性。通过今天的学习,总结如下:1、Object 类是 DTLib 库中数据结构类的顶层父类;2、Object 类用于统一动态内存申请的行为;3、在堆中创建 Object 子类的对象,失败时返回 NULL 值;4、Object 类为纯虚父类,所有子类都能进行动态类型识别。至此我们的库的基础设施构建基本已经完成:顶层父类、智能指针、异常类


指针 对象 顶层 函数 源码 代码 子类 行为 内存 准则 智能 移植性 C++ 中创 开发 移植 设计 也就是 信息 动态 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 宁波营销软件开发服务 什么是软件开发职业培训 通达信 自定义序列数据库 中国项目管理软件开发公司 兰溪软件开发培训 中国电信网络技术工程师考试 查看数据库的归档 网络安全宣传周网络知识竞赛 软件开发常用问题 h3c无线管理服务器 计算机网络技术具备能力 保障数据库安全的机制 网络安全策略可视化管理软件 ado 数据库连接属性 长治网络技术参数 软件开发是否能用别人的语音 凤阳工业软件开发技术代理商 主流软件开发过程 服务器是信息安全产品吗 数据库范式美学设计 软件开发编程技术课程 国家网络安全战略的战略目标 数据库显示无法编译jsp文件 e城e家燃气缴费服务器内部错误 软件开发项目风险识别的清单 南京财务软件开发公司 网络安全策略可视化管理软件 青岛大的软件开发公司 数据库表分析什么意思 全威互联网信息科技有限公司
0