C++以数组类封装巩固C++基础知识


前言

结合C++基础知识完成对数组类的封装(能对自己定义的类存储赋值操作)


一、知识点汇总

  1. C++三大特性:继承、多态、封装
  2. 多文件编写代码操作hpp
  3. 模板
  4. 赋值运算符重载
  5. 构造函数(无参、有参、浅拷贝与深拷贝差异)、析构函数

二、为什么要写数组类的封装?

  • 当出现不是编译器已经定义好的类型如char,int,double之类的类型之外,我们如何操作呢? 这个时候就需要自己定义一个数组类能实现对其他类的数据存储

三、代码实现

  1. T* pAddress 指针指向堆区开辟的真实数组
  2. int m_Capacity 数组容量
  3. int m_Size 数组大小
  • 代码如下(示例):MyArray.hpp文件中
#pragma once
#include <iostream>

using namespace std;

template <class T>
class MyArray
{
public:
	//有参构造 
	MyArray(int capacity)
	{
//		cout << "有参构造调用" << endl;
		this->m_Capacity = capacity;
		this->m_Size = 0;
		this->pAddress = new T[this->m_Capacity];
	}
	
	//拷贝构造 传引用 
	MyArray(const MyArray &arr)
	{
//		cout << "拷贝构造调用" << 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++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}
	
	//operator=重载= 防止浅拷贝问题 a = b = c左值 所以返回引用 
	MyArray& operator=(const MyArray& arr)
	{
//		cout << "operator=调用" << endl;
		//先判断原来堆区是否有数据 如有先释放
		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 < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
		
		//返回自身 *this对应MyArray
		return *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 ;
		}
		
//		delete [] this->pAddress[this->m_Size];
//		this->pAddress[this->m_Size] = NULL;
		this->m_Size--;
//		this->m_Capacity--;
	}
	
	//通过下标方式访问数组中元素	arr[0]=100
	T& operator[](int index)
	{
		return this->pAddress[index];
	}
	
	//返回数组容量
	int getCapacity()
	{
		return this->m_Capacity;
	}
	
	//返回数组大小
	int getSize()
	{
		return this->m_Size;
	}
	
	//析构函数
	~MyArray()
	{
		if(this->pAddress != NULL)
		{
//			cout << "析构函数调用" << endl;
			delete [] this->pAddress;
			this->pAddress = NULL;
		}
	}

private:
	T* pAddress;	//指针指向堆区开辟的真实数组
	
	int m_Capacity;	//数组容量
	 
	int m_Size;	//数组大小 
};

数组类封装.cpp文件中

#include <iostream>
#include <string>
#include "MyArray.hpp"

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

void printIntArray(MyArray<int>& arr)
{
	for(int i = 0; i < arr.getSize(); i++)
	{
		cout << arr[i] << endl;//中括号重载 
	}
}
class Person
{
public:
	Person() {
	};
	
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	
	string m_Name;
	int m_Age;
	
};

//模板类做函数参数时一定要有<>里面填数据类型
void printPersonArray(MyArray<Person>& arr) 
{
	for(int i = 0; i < arr.getSize(); i++)
	{
		cout << "姓名:" << arr[i].m_Name << "年龄:" << arr[i].m_Age << endl;
	}
}

void test02()
{
	//模板类定义变量时也需要<>里面填数据类型
	MyArray<Person> arr(10);
	
	Person p1("孙悟空", 999);
	Person p2("韩信", 20);
	Person p3("妲己", 30);
	Person p4("赵云", 25);
	Person p5("安其拉", 27);
	
	//将数据插入到数组中
	arr.Push_Back(p1);
	arr.Push_Back(p2);
	arr.Push_Back(p3);
	arr.Push_Back(p4);
	arr.Push_Back(p5);
	
	//打印数组
	printPersonArray(arr);
	
	//输出容量
	cout << "arr容量为:" << arr.getCapacity() << endl;
	
	//输出大小
	cout << "arr大小为:" << arr.getSize() << endl; 
	
}

int main(int argc, char** argv) 
{
	//test01();
	test02();
	return 0;
}

总结

  • 由于pAddress为指针在构造函数调用的时候一定要注意深浅拷贝的问题
    深浅拷贝存在的问题:由于指针的出现,如果是浅拷贝(p1,p2会同时指向堆区一块内存)在调用析构函数的时候会存在重复释放空间的问题。如果是深拷贝(p1,p2不会指向同一块堆区数据)析构时也会走各自的析构函数 不会存在重复析构的问题
  • 有参构造中this->pAddress = new T[this->m_Capacity]; 这里强调下new的用法new + 数据类型[n]表示在堆区开辟一个长度为this->m_Capacity 数据类型为T的数组 用this->pAddress指针指向其首地址
  • 拷贝构造MyArray(const MyArray &arr)传入参数为引用
    引用的优点:相比指针,引用更加安全。引用相当于是变量的“别名”,对引用进行操作就像对原变量进行操作一样
  • 赋值运算符的重载,MyArray& operator=(const MyArray& arr) 为什么需要返回MyArray&?—> 由于a=b=c这种运算方式则需要返回其左值以实现这种连等式的运算,返回MyArray&也就是返回自己 所以函数末尾写return *this
    因为赋值操作会改变左值,而 + 之类的运算符不会改变操作数,所以说赋值运算符重载要返回引用以用于类似 (a=b)=c 这样的再次对a=b进行写操作的表达式。
  • []的重载,因为arr是自己定义的数据类型的变量所以编译器不能识别[],则需要对[]的重载
	T& operator[](int index)
	{
		return this->pAddress[index];
	}

这样就能识别[]

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值