文章目录
- 概要
- 根据代码和输出进行分析(看注释和图示)
- 个人小结
概要
案例描述: 实现一个通用的数组类,要求如下:
- 可以对内置数据类型以及自定义数据类型的数据进行存储;
- 将数组中的数据存储到堆区;
- 构造函数中可以传入数组的容量;
- 提供对应的拷贝构造函数以及operator=防止浅拷贝问题;
- 提供尾插法和尾删法对数组中的数据进行增加和删除;
- 可以通过下标的方式访问数组中的元素;
- 可以获取数组中当前元素个数和数组的容量。
根据代码和输出进行分析(看注释和图示)
MyArray.hpp代码:
#pragma once
#include<iostream>
using namespace std;
template<class T>
class MyArray
{
public:
//有参构造 参数 容量
MyArray(int capacity)
{
cout << "MyArray的有参构造调用" << endl;
this->m_Capacity = capacity; // 期望所存
this->m_Size = 0; //现存
this->pAddress = new T[this->m_Capacity];
}
//拷贝构造函数 防止浅拷贝问题
MyArray(const MyArray& arr)
{
cout << "MyArray的拷贝构造调用" << endl;
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
// this->pAddress = arr.pAddress; //默认拷贝构造函数会这么写,造成堆区数据重复释放
//深拷贝
this->pAddress = new T[arr.m_Capacity];
//将arr中的数据都拷贝过来
for (int i = 0; i < this->m_Size; i++)
{
// 如果T为对象,而且还包含指针,必须需要重载 = 操作符,因为这个等号不是 构造 而是赋值,
// 普通类型可以直接= 但是指针类型需要深拷贝
this->pAddress[i] = arr.pAddress[i];
}
}
//operator= 防止浅拷贝问题 a=b=c 自带的=能实现链式编程
MyArray& operator=(const MyArray& arr)
{
cout << "MyArray的operator=赋值运算符重载调用" << endl;
//先判断原来堆区是否有数据,如果有先释放
if (this->pAddress != nullptr){
delete [] this->pAddress;
this->pAddress = nullptr;
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 < this->m_Capacity; i++){
this->pAddress[i] = arr.pAddress[i];
}
return *this; //MyArray& = *this
}
//尾插法
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& operator[] (int index){ //arr[0] = 100 为了让它可以做左值,需要返回T的引用 这种思想也是链式编程思想
return this->pAddress[index];
}
//返回数组容量
int getCapacity(){
return this->m_Capacity;
}
//返回数组大小
int getSize(){
return this->m_Size;
}
//析构函数
~MyArray()
{
cout << "MyArray的析构函数调用" << endl;
if(this->pAddress != nullptr){
delete [] this->pAddress; //指向的是数组
this->pAddress = nullptr; //指针置空,防止野指针
}
}
private:
T * pAddress;
int m_Capacity;
int m_Size;
};
Main.cpp代码
#include <iostream>
#include "MyArray.hpp"
#include <windows.h>//用于函数SetConsoleOutputCP(65001);更改cmd编码为utf8
#include <string>
using namespace std;
void PrintIntArray(MyArray<int> arr) //会调用拷贝构造函数,如果写成MyArray<int> &arr就不会调用了!
{
for (int i =0; i < arr.getSize(); i++){
cout << arr[i] << endl;
}
}
//测试内置数据类型
void test01(){
MyArray<int> arr1(5); //有参构造 数据放在栈上
for (int i = 0; i < 5; i++){
arr1.Push_Back(i); // 尾插法
}
cout << "arr1的打印输出:" << endl;
PrintIntArray(arr1);
cout << "arr1的容量:" << arr1.getCapacity() << endl;
cout << "arr1的大小:" << arr1.getSize() << endl;
MyArray<int>arr2(arr1);//拷贝构造
cout << "arr2的打印输出:" << endl;
PrintIntArray(arr2);
//尾删
arr2.Pop_Back();
cout << "arr2尾删后:" << endl;
cout << "arr2的容量:" << arr2.getCapacity() << endl;
cout << "arr2的大小:" << arr2.getSize() << endl;
MyArray<int>arr3(100); //有参构造
arr3 = arr1; //等号赋值
}
int main(){
SetConsoleOutputCP(65001);
test01();
cout <<"执行完毕" <<endl;
system("pause");
return 0;
}
输出与解释:
我有个点不太确定,请大佬指正是否正确:因为arr1 2 3是创建在栈上的局部变量,所以遵循先进后出的原则释放,所以先释放arr3,然后依次释放arr2、arr1。
个人小结
上面这个案例很好的总结了C++有关类和函数的相关核心知识,获益匪浅。
花了两个多星期,黑马的课程终于看到STL模板库了,后面继续学习加油吧(ง •_•)ง