文章目录
- 前言
- 一、为什么需要创建顶层父类
- 二、创建顶层父类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++中创建顶层父类以支持数据结构的设计。