案例描述: 实现一个通用的数组类,要求如下:
- 可以对内置数据类型以及自定义数据类型的数据进行存储
- 将数组中的数据存储到堆区
- 构造函数中可以传入数组的容量
- 提供对应的拷贝构造函数以及operator=防止浅拷贝问题
- 提供尾插法和尾删法对数组中的数据进行增加和删除
- 可以通过下标的方式访问数组中的元素
- 可以获取数组中当前元素个数和数组的容量
小总结:“拷贝构造” 和 "=赋值 *** 作 " 如果遇到有在堆区开辟的数据,都会有浅拷贝的问题,要写成深拷贝避免重复释放内存。
具体写法见以下代码:
#ifndef _MYARRAY_HPP_//防止头文件重复包含 #define _MYARRAY_HPP_ #include主cpp:#include using namespace std; template class MyArray { public: MyArray(int Capacity)//有参构造函数 { cout << "有参构造函数调用" << endl; this->m_Capacity = Capacity; this->m_Size = 0;//初始化数组中元素个数为0 this->pAddress = new T[this->m_Capacity];//开辟对应数据类型的空间 } MyArray(const MyArray& arr)//1、自己写拷贝构造函数 防止浅拷贝问题 { cout << "拷贝构造函数调用" << endl; this->m_Capacity = arr.m_Capacity; this->m_Size = arr.m_Size; //this->pAddress = arr.pAddress;//编译器提供的,指针简单赋值,最后会导致重复释放内存 this->pAddress = new T[this->m_Capacity];//深拷贝 for (int i = 0; i < m_Size; i++)//原来数组中可能已经有数据了,所以要把数据都拷贝过来 { this->pAddress[i] = arr.pAddress[i]; } } MyArray& operator=(const MyArray& myarray)//2、重载= 运算符 防止浅拷贝问题 { cout << "=赋值函数调用" << endl; if (this->pAddress != NULL) //先判断原来堆区是否有数据,如果有先释放 { delete[] this->pAddress; this->m_Capacity = 0; this->m_Size = 0; } this->m_Capacity = myarray.m_Capacity; this->m_Size = myarray.m_Size; this->pAddress = new T[this->m_Capacity]; for (int i = 0; i < this->m_Size; i++) { this->pAddress[i] = myarray.pAddress[i]; } return *this;//返回对象本身,形成链式编程 } int getCapacity()//获取数组的容量 { return this->m_Capacity; } int getSize()//获取数组的大小 { return this->m_Size; } ~MyArray()//析构函数 { cout << "析构函数调用" << endl; if (pAddress != NULL) { delete[] pAddress; pAddress = NULL; this->m_Capacity = 0; this->m_Size = 0; } } public: T* pAddress; //指向一个堆空间,这个空间存储真正的数据,传进来什么样的数据类型,就开辟对应类型的空间 int m_Capacity;//数组容量,一共可以存储多少个数据 int m_Size; //数组中元素的个数,存完之后数组的元素个数 }; #endif // !_MYARRAY_HPP_
#include现象: 2、第二版实现功能代码: myarray.hpp :#include #include"myarray.hpp"//包含类模板头文件 using namespace std; int main() { MyArray arr1(10);//调用有参构造 MyArray arr2(arr1);//调用拷贝构造 MyArray arr3(10);//赋值 *** 作 arr3 = arr1; return 0; }
#ifndef _MYARRAY_HPP_//防止头文件重复包含 #define _MYARRAY_HPP_ #include主cpp :#include using namespace std; template class MyArray { public: MyArray(int Capacity)//有参构造函数 { this->m_Capacity = Capacity; this->m_Size = 0;//初始化数组中元素个数为0 this->pAddress = new T[this->m_Capacity];//开辟对应数据类型的空间 } MyArray(const MyArray& arr)//1、自己写拷贝构造函数 防止浅拷贝问题 { if (this->pAddress != NULL) //先判断原来堆区是否有数据,如果有先释放 { delete[] this->pAddress; this->m_Capacity = 0; this->m_Size = 0; } this->m_Capacity = arr.m_Capacity; this->m_Size = arr.m_Size; //this->pAddress = arr.pAddress;//编译器提供的,指针简单赋值,最后会导致重复释放内存 this->pAddress = new T[this->m_Capacity];//深拷贝 for (int i = 0; i < m_Size; i++)//原来数组中可能已经有数据了,所以要把数据都拷贝过来 { this->pAddress[i] = arr.pAddress[i]; } } MyArray& operator=(const MyArray& myarray)//2、重载= 运算符 防止浅拷贝问题 { if (this->pAddress != NULL) //先判断原来堆区是否有数据,如果有先释放 { delete[] this->pAddress; this->m_Capacity = 0; this->m_Size = 0; } this->m_Capacity = myarray.m_Capacity; this->m_Size = myarray.m_Size; this->pAddress = new T[this->m_Capacity]; for (int i = 0; i < this->m_Size; i++) { this->pAddress[i] = myarray.pAddress[i]; } return *this;//返回对象本身,形成链式编程 } T& operator[](int index)//重载[]运算符,实现用下标方式访问数组 例如:arr[1]=100; { return this->pAddress[index]; //注意返回值的类型要为引用,即返回一个地址,它要作为左值存在,因为你可以修改他的值嘛 } void Push_back(T& data)//尾插法 向数组中插入数据 { //插入之前先判断一下数组是否还有空间,容量是否等于大小 if (this->m_Capacity == this->m_Size) { cout << "数组没有空间了" << endl; return; } this->pAddress[this->m_Size] = data;//在数组末尾插入数据,即尾插 this->m_Size++;//更新数组大小 } void Pop_back()//尾删法 每调用一次,就从数组最后删除一个数据 { //删除之前要判断一下,数组的状态,如果数组中已经没有数据了,那就没法删了 if (this->m_Size == 0) { cout << "数组中已没有数据,无法删除" << endl; return; } this->m_Size--;//把数组的大小减一,往前移一个位置让用户访问不到就可以了,即为逻辑删除 } int getCapacity()//获取数组的容量 { return this->m_Capacity; } int getSize()//获取数组的大小 { return this->m_Size; } ~MyArray()//析构函数 { if (pAddress != NULL) { delete[] pAddress; pAddress = NULL; this->m_Capacity = 0; this->m_Size = 0; } } private: T* pAddress; //指向一个堆空间,这个空间存储真正的数据,传进来什么样的数据类型,就开辟对应类型的空间 int m_Capacity;//数组容量,一共可以存储多少个数据 int m_Size; //数组中元素的个数,存完之后数组的元素个数; 当前数组的大小 }; #endif // !_MYARRAY_HPP_
#include#include #include"myarray.hpp"//包含类模板头文件 using namespace std; void PrintInt(MyArray & array)//将打印整型数组元素封装成一个函数 { for (int i = 0; i < array.getSize(); i++) { cout << array[i] << " "; } cout << endl; } void test01() { MyArray arr1(10);//调用有参构造 cout << arr1.getCapacity() << endl; cout << arr1.getSize() << endl; MyArray arr2(arr1);//调用拷贝构造 cout << arr2.getCapacity() << endl; cout << arr2.getSize() << endl; MyArray arr3(10);//赋值 *** 作 arr3 = arr1; } void test02() { MyArray arr(10);//设置数组的容量大小 for (int i = 0; i < 10; i++)//往数组中插入数据 { arr.Push_back(i); } arr[0] = 100;//设置数组中第一个元素值为100 arr.Pop_back();//删除一个元素 PrintInt(arr);//打印数组中的数据 cout << "----------------------------" << endl; MyArray arr2(arr);//调用拷贝构造复制arr的值 arr2.Pop_back(); cout << "数组容量:" << arr2.getCapacity() << " " << "数组大小:" << arr2.getSize() << endl; PrintInt(arr2);//打印数组中的数据 } class Person { public: Person() { //cout << "默认构造调用" << endl; } Person(string name, int age) { //cout << "有参构造调用" << endl; m_name = name; m_age = age; } ~Person() { //cout << "析构调用" << endl; } public: string m_name; int m_age; }; void PrintPerson(MyArray & p)//将打印Person类型数组封成一个函数 { for (int i = 0; i < p.getSize(); i++) { cout << p[i].m_name<<" "< parray(10);//创建Person类型的数组,并声明数组容量 Person p1("张三", 20); Person p2("李四", 21); Person p3("王五", 22); Person p4("赵六", 23); parray.Push_back(p1); parray.Push_back(p2); cout << "容量:" << parray.getCapacity() << " " << "大小:" << parray.getSize() << endl; PrintPerson(parray); } int main() { test01();//测试基本功能 test02();//测试int类型数组 test03();//测试自定义Perosn类型数组 return 0; }
总结:
这个案例综合性还是比较强的,通过做这个案例,把之前的运算符重载,拷贝构造,类模板知识都复习了一遍,这个案例以后还是经常多敲几遍比较好,巩固一下
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)