【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

相关文章

使用Python创建一个功能完整的Windows风格计算器程序

《使用Python创建一个功能完整的Windows风格计算器程序》:本文主要介绍如何使用Python和Tkinter创建一个功能完整的Windows风格计算器程序,包括基本运算、高级科学计算(如三... 目录python实现Windows系统计算器程序(含高级功能)1. 使用Tkinter实现基础计算器2.

CentOS和Ubuntu系统使用shell脚本创建用户和设置密码

《CentOS和Ubuntu系统使用shell脚本创建用户和设置密码》在Linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设置密码,本文写了一个shell... 在linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设

C#如何调用C++库

《C#如何调用C++库》:本文主要介绍C#如何调用C++库方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录方法一:使用P/Invoke1. 导出C++函数2. 定义P/Invoke签名3. 调用C++函数方法二:使用C++/CLI作为桥接1. 创建C++/CL

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元