案例描述: 实现一个通用的数组类,要求如下:
可以对内置数据类型以及自定义数据类型的数据进行存储。
将数组中的数据存储到堆区
构造函数中可以传入数组的容量
提供对应的拷贝构造函数以及operator=防止浅拷贝问题
提供尾插法和尾删法对数组中的数据进行增加和删除
可以通过下标的方式访问数组中的元素
可以获取数组中当前元素个数和数组的容量
需求分析: 一、类的基本结构:
设计一个MyArray的类,类内属性为:
类内维护一个数组:T* item = new T[5];维护表示一个关于数组容量的属性:m_Capacity。维护表示一个数组元素个数的属性:m_Size。
属性写为private权限。
二、数据结构:维护的这个数组要开辟到堆区。在堆区中维护的这个数据类型必须是通用的,即泛型的,支持多样性。所以堆中数组元素类型为T。
为此:数组中每个元素为 T* item = new T[5];
三、接口功能:对外要提供一些功能函数接口:public:
构造函数(传入容量):传入参数,指定数组的容量。拷贝构造:operator=:运算符重载。类内存在堆区的数据,为了防止 浅拷贝重复释放 的问题。利用下标的方式:访问数组元素尾插法:尾删法:获取数组的容量获取数组的元素个数。析构函数:
四:一步步实施:
这个需要内容比较多,不适合写在一个文件里面,所以分文件写:类模板分文件的编写,最好将声明和实现写在一起:都放在.hpp文件中。
先写一个类模板的文件:MyArray.hpp文件。
#includeusing namespace std; template class MyArray { public: // 初始化:有参构造 参数 容量 MyArray(int capacity) { this->m_Capacity = capacity; this->m_Size = 0; this->pAddress = new T[this->m_Capacity]; // 测试代码: cout << "MyArray 有参构造 被调用。" << endl; } // 拷贝构造 MyArray(const MyArray& arr) { this->m_Capacity = arr.m_Capacity; this->m_Size = arr.m_Size; //this->pAddress // 开辟在堆区,所以需要深拷贝,从堆中,重新开辟一块空间,拷贝过去。 this->pAddress = new T[arr.m_Capacity]; // 将arr中的数据都拷贝过来。 for (int i = 0; i < this->m_Size; i++) { this->pAddress[i] = arr.pAddress[i]; } cout << "MyArray 拷贝构造 被调用。" << endl; } // operator= 防止浅拷贝问题。 MyArray& operator=(const MyArray& arr) { // 先判断原来堆区是否有数据。如果有先释放 if (this->pAddress != NULL) { delete[] this->pAddress; this->pAddress = NULL; this->m_Capacity = 0; this->m_Size = 0; } // 然后深拷贝: this->m_Capacity = arr.m_Capacity; this->m_Size = arr.m_Size; this->pAddress = new T[arr.m_Capacity]; // 数据全拷贝。 for (int i = 0; i < arr.m_Capacity; i++) { this->pAddress[i] = arr.pAddress[i]; } cout << "MyArray 运算符重载operator= 被调用。" << endl; return *this; // 返回自身。 } // 析构函数: ~MyArray() { if (this->pAddress!=NULL) { delete[] this->pAddress; this->pAddress = NULL; // 置空,防止称为野指针。 cout << "MyArray 析构函数 被调用。" << endl; } } private: T* pAddress; // 指针指向堆区开辟的真实的数组。 int m_Capacity; // 数组的容量 int m_Size; // 数组的大小 };
先把基本框架写出来,然后做个测试:在程序中写一个测试案例。补充打印测试。
先包含头文件:#include "MyArray.hpp"
void test01() { int len = 5; MyArrayarr(len); MyArray arr1(arr); // 拷贝构造方式。 MyArray arr2(10); arr2 = arr; // 运算符重载。 }
阶段性测试:已经完成前面几个任务,只剩下最后三个任务:
先写:尾插法、尾删法
// 尾插法 void Push_Back(const T& val) { // 插入之前先判断容量是否等于大小。 if (this->m_Capacity == this->m_Size) { return; } this->pAddress[this->m_Size] = val; // 在数组末尾插入数据。 this->m_Size++; // 更新数组大小。 } // 尾删法 void Pop_Back() { // 让用户访问不到最后一个元素。即为尾删,逻辑删除。 if (this->m_Size == 0) { return; } this->m_Size--; }
下标访问:
// 下标访问元素:返回类型为元素类型T,如果需要将返回值作为左值存在,那么需要返回引用。 T& operatoar[](int index) { return this->pAddress[index]; }
返回数组容量、大小
// 返回数组容量 int getCapacity() { return this->m_Capacity; } // 返回数组大小 int getSize() { return this->m_Size; }
为了打印输出,我写了个友元来显示每一项:
friend void printArray(const MyArray& arr) { for (int i = 0; i < arr.m_Size; i++) { cout << arr.pAddress[i] << " "; } cout << endl; }
void test01() { int len = 5; MyArrayarr(len); MyArray arr1(arr); // 拷贝构造方式。 MyArray arr2(10); arr2 = arr; // 运算符重载。 } void test02() { int len = 5; MyArray arr(len); for (int i = 0; i < len; i++) { arr.Push_Back(i + 1); } cout << "初始化arr:"; printIntArray(arr); // 友元; // 测试尾删法: arr.Pop_Back(); cout << "测尾删arr:"; printIntArray(arr); // 友元; // 测试尾插法; arr.Push_Back(99); printIntArray(arr); // 友元; cout << arr.getCapacity() << endl; cout << arr.getSize() << endl; }
以上是关于内置数据类型的案例。来看看自定义类型案例。
#pragma once #includeusing namespace std; template class Person { public: Person() {}; // 不加这个默认构造函数,会报错。 Person(T1 name, T2 age); void showPerson(); private: T1 m_Name; T2 m_Age; }; // 类外实现 template Person ::Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } template void Person ::showPerson() { cout << "姓名:" << this->m_Name << ", 年龄:" << this->m_Age << endl; }
我们直接套用前面几节中关于Person.hpp的类模板。然后来测试。
void printPersonArray(MyArray>& arr) { for (int i = 0; i < arr.getSize(); i++) { arr[i].showPerson(); } } // 看看自定义类数组效果 void test03() { Person p1("张三", 18); Person p2("李四", 14); Person p3("王五", 15); Person p4("赵六", 16); Person p5("田七", 17); MyArray > arr(5); arr.Push_Back(p1); arr.Push_Back(p2); arr.Push_Back(p3); arr.Push_Back(p4); arr.Push_Back(p5); printPersonArray(arr); }
报错了;
没有合适的默认构造函数可用。因此需要在Person.hpp中,将默认构造函数,加进去,即:Person(){}。否则会报上面的错误。
类模板中引用其他类模板,被引用类模板要加上默认构造函数。
此外两个深拷贝存在这样一个问题:待我技术成长了再来解决。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)