【C++数据结构】顶层父类的创建与类族结构的进化

2023-11-08 16:20

本文主要是介绍【C++数据结构】顶层父类的创建与类族结构的进化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 一、为什么需要创建顶层父类
  • 二、创建顶层父类Object的意义
  • 三、创建顶层父类Object
    • 3.1 顶层父类接口
    • 3.2 Object具体实现
      • new和delete运算符重载的实现
      • == 和 != 的运算符重载实现
    • 3.3 纯虚析构函数实现
  • 四、类族的结构进化
    • 4.1 怎样进化
    • 4.2 SmartPointer的进化
    • 4.3 Exception类的进化
  • 总结


前言

在C++中,数据结构是编程的重要组成部分,用于组织和管理数据。为了更好地组织代码和实现代码重用,创建一个顶层父类在数据结构中具有重要意义。这个父类可以为不同数据结构提供通用的接口和行为,同时允许具体的数据结构类继承这些通用特性并添加自己特有的功能。本文将介绍如何在C++中创建这样的顶层父类,为不同数据结构的设计和实现提供了框架和结构。


一、为什么需要创建顶层父类

顶层父类的创建

  • 当代软件架构实践中的经验
  • 尽量使用单重继承的方式进行系统设计
  • 尽量保持系统中只存在单一的继承树

不幸的事实:

  • C++ 语言的灵活性使得代码中可以存在多个继承树
  • C++ 编译器的差异使得同样的代码可能表现不同的行为
    new 操作如果失败会发生什么 ?
    在不同的编译器和环境下都会有所差异。
    例如在vs的开发环境下,可以抛出一个exception
    在其他的开发环境下可能是空指针。
    那么这样就不可控,就大大降低我们的可移植性。

所以我们需要一个顶层父类来帮助我们

二、创建顶层父类Object的意义

创建 DbTLib: :0bject 类的意义

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

三、创建顶层父类Object

3.1 顶层父类接口

class Object
{
public:/*throw()不会抛出异常*/void* operator new (size_t size) throw();void operator delete (void* p);void* operator new[](size_t size) throw();void operator delete[](void* p);bool operator == (const Object& obj);bool operator != (const Object& obj);virtual ~Object() = 0;
};

在这里插入图片描述

上面的代码定义了一个名为 Object 的C++类,其中包含了一些特殊的成员函数和声明。下面逐句解释这些代码:

1.class Object:
这一行定义了一个名为 Object 的C++类。这将是一个基类,其他类可以从它派生。
2.public::
这行指示以下成员函数和数据成员在类的公共部分,即可以在类的外部访问。
3.void* operator new (size_t size) throw(); :
这是一个重载的 new 运算符。它用于动态分配内存并返回一个指向该内存的指针。 size_t size 是要分配的内存块的大小。 throw() 关键字表示此运算符不会抛出异常。
4.void operator delete (void* p); :
这是一个重载的 delete 运算符。它用于释放通过 new 分配的内存。参数 void* p 是要释放的内存块的指针。
5.void* operator new[](size_t size) throw(); :
这是重载的数组 new 运算符,用于分配数组形式的内存块,并返回一个指向该内存的指针。 size_t size 指定要分配的内存块的总大小。同样,throw() 表示不会抛出异常。
6.void operator delete[](void* p); :
这是重载的数组 delete 运算符,用于释放通过数组 new 分配的内存。参数 void* p 是要释放的内存块的指针。
7.bool operator == (const Object& obj); :
这是一个自定义的相等运算符重载,用于比较两个 Object 类对象是否相等。
8.bool operator != (const Object& obj); :
这是一个自定义的不等运算符重载,用于比较两个 Object 类对象是否不相等。
9.virtual ~Object() = 0; :
这是 Object 类的虚析构函数。通过在其声明中使用 = 0,它被声明为纯虚函数。这意味着 Object 类是一个抽象基类,不能被实例化,只能用作其他类的基类。任何派生自 Object 的类都必须提供自己的析构函数实现。虚析构函数通常用于确保在派生类中的资源正确释放。

总的来说,这个 Object 类定义了一些特殊的成员函数,使其成为一个抽象基类,为其他类提供了通用的内存分配、释放、比较等功能。其他类可以继承自 Object 类,并实现其纯虚析构函数以添加自己的功能。这种设计通常用于创建一个对象层次结构,其中多个类共享一些通用行为。

3.2 Object具体实现

new和delete运算符重载的实现

我们需要想一下,如何申请空间才是可控的,不会抛出异常的。
当然是我们的malloc函数和free函数啦

所以在外面这个Object里面使用这两个函数来实现我们的运算符重载

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没有提供任何的flag标识和标识我们这个类是谁

所以我们需要使用一种质朴的方法:比较内存地址,内存地址一样肯定是一样的东西,因为他们指向同一块空间。

bool Object::operator == (const Object& obj)
{return (this == &obj);
}bool Object::operator != (const Object& obj)
{return (this != &obj);
}

在这里插入图片描述

3.3 纯虚析构函数实现

这里的析构并不需要实现具体功能,只需要写个函数体即可

Object::~Object()
{}

四、类族的结构进化

4.1 怎样进化

我们需要写出一个单继承数,如下图:
在这里插入图片描述
我们下面的所有类都要继承Object父类,那么接下来我们就去实现他吧

4.2 SmartPointer的进化

我们直接进行继承即可,不需要改动

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

在这里插入图片描述

4.3 Exception类的进化

和上面一样,我们也只需要进行简单的继承即可:

class Exception:public Object
{
protected:char* m_message;char* m_location;//.............
}

在这里插入图片描述

但是我想各位同学应该发现了一个问题,就是在我们的init函数中申请了空间,没有进行判断是否为空。
那么我们就去改吧:

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分支呢,是否需要throw抛出异常呢,其实是不需要的。我们只需要判断是否为空即可,然后进行对应的操作


总结

在C++中,创建顶层父类对于数据结构的设计和实现是非常有益的。它提供了通用的接口和行为,使得代码更易维护和扩展。通过继承和实现,具体的数据结构类可以在保持通用性的同时添加自己特有的功能。这种层次结构的设计有助于提高代码的可重用性和可读性,同时促进了良好的编程实践。希望本文能够帮助你更好地理解如何在C++中创建顶层父类以支持数据结构的设计。

这篇关于【C++数据结构】顶层父类的创建与类族结构的进化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/371047

相关文章

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C

C++链表的虚拟头节点实现细节及注意事项

《C++链表的虚拟头节点实现细节及注意事项》虚拟头节点是链表操作中极为实用的设计技巧,它通过在链表真实头部前添加一个特殊节点,有效简化边界条件处理,:本文主要介绍C++链表的虚拟头节点实现细节及注... 目录C++链表虚拟头节点(Dummy Head)一、虚拟头节点的本质与核心作用1. 定义2. 核心价值二

python如何创建等差数列

《python如何创建等差数列》:本文主要介绍python如何创建等差数列的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python创建等差数列例题运行代码回车输出结果总结python创建等差数列import numpy as np x=int(in

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2