案例實現:實現一個通用的數組類,要求如下:
- 可以對內置數據類型以及自定義數據類型的數據進行存儲
- 將數組中的數據存儲到堆區
- 構造函數中可以傳入數組的容量
- 提供對應的拷貝構造函數以及operator=防止淺拷貝問題
- 提供尾插法和尾刪法對數組中的數據進行增加和刪除
- 可以通過下標的方式訪問數組中的元素
- 可以獲取數組中當前元素個數和數組的容量
因為我們并不知道里面有什么數據類型,因此我們需要將這些數據進行模版化。
首先我們在MyArray.hpp文件里面寫入以下的代碼
//自己的通用的數組類
#include <iostream>
using namespace std;template<typename T>
class MyArray{public://有參構造函數 參數 容量MyArray(int capacity){cout<<"MyArray有參構造調用"<<endl;this->m_Capacity=capacity;//數組初始化的大小為0this->m_Size=0;this->pAddress=new T[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];//將原數組的元素拷貝到新數組中for(int i=0;i<this->m_Capacity;i++){this->pAddress[i]=arr.pAddress[i];}}//operator= 也是為了防止淺拷貝問題. a=b=cMyArray &operator=(const MyArray &arr){cout<<"MyArray賦值運算符調用"<<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_Size;i++){this->pAddress[i]=arr.pAddress[i];//將原數組的元素拷貝到新數組中}return *this;//返回當前對象的引用}//之后再去做一個深拷貝//析構函數~MyArray(){if(this->pAddress!=nullptr){cout<<"MyArray析構函數調用"<<endl;delete[] this->pAddress;//防止其為一個野指針this->pAddress=nullptr;}}private:T* pAddress; //指針指向堆區開辟的真實的數組int m_Capacity;//數組的容量int m_Size;//數組的元素個數(數組的大小)
};
在數組類封裝.cpp這個文件里面寫入下面的代碼
#include <iostream>
using namespace std;
#include "MyArray.hpp"void test01()
{MyArray<int> arr1(5); // 創建一個容量為5的數組MyArray<int> arr2(arr1); // 使用拷貝構造函數創建一個新數組MyArray<int> arr3(100); // 使用賦值運算符進行賦值arr3=arr1;// 使用賦值運算符進行賦值
}int main()
{test01(); // 測試函數return 0; // 返回0表示程序正常結束
}
之后運行,我們可以得到以下的內容
也就是說我們這幾個進行了深拷貝,還有有參構造,之后通過析構函數釋放了它們的內存。
MyArray.hpp
//自己的通用的數組類
#include <iostream>
using namespace std;template<typename T>
class MyArray{public://有參構造函數 參數 容量MyArray(int capacity){this->m_Capacity=capacity;//數組初始化的大小為0this->m_Size=0;this->pAddress=new T[capacity]; //開辟堆區空間}//為了防止淺拷貝的問題,還必須寫一個拷貝構造函數MyArray(const MyArray &arr){this->m_Capacity=arr.m_Capacity;this->m_Size=arr.m_Size;//潛拷貝//this->pAddress=arr.pAddress; //將原數組的地址賦值給新數組//開辟新的堆區空間this->pAddress=new T[arr.m_Capacity];//將原數組的元素拷貝到新數組中for(int i=0;i<this->m_Capacity;i++){this->pAddress[i]=arr.pAddress[i];}}//operator= 也是為了防止淺拷貝問題. a=b=cMyArray &operator=(const MyArray &arr){//先判斷原來堆區是否有數據,如果有先釋放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_Size;i++){this->pAddress[i]=arr.pAddress[i];//將原數組的元素拷貝到新數組中}return *this;//返回當前對象的引用}//尾插法//一般為了防止T被修改,因此我們一般會寫入一個const修飾符void Push_Back(const T &val){//判斷數組是否已滿if(this->m_Size>=this->m_Capacity) {cout<<"數組已滿,無法插入元素"<<endl;return;}else{this->pAddress[this->m_Size]=val; //將元素插入到數組的末尾this->m_Size++;//元素個數加1}}//尾刪法void Pop_Back(){if(this->m_Size<=0){cout<<"數組為空,無法刪除元素"<<endl;return;}else{//讓用戶訪問不到最后一個元素就可以了this->m_Size--;//元素個數減1//不需要刪除最后一個元素,因為數組的大小已經減小了}}//通過下標的方式訪問數組中的元素T& operator[](int index){return this->pAddress[index]; //返回數組中指定下標的元素}//返回數組的容量int GetCapacity() const{return this->m_Capacity;}//返回數組的大小int GetSize() const{return this->m_Size;}//析構函數~MyArray(){if(this->pAddress!=nullptr){delete[] this->pAddress;//防止其為一個野指針this->pAddress=nullptr;}}private:T* pAddress; //指針指向堆區開辟的真實的數組int m_Capacity;//數組的容量int m_Size;//數組的元素個數(數組的大小)
};
數組類封裝函數那里寫
#include <iostream>
using namespace std;
#include "MyArray.hpp"
#include <string>void printIntArray(MyArray<int> &arr)
{for(int i=0;i<arr.GetSize();i++){cout<<arr[i]<<" "<<endl;}
}
void test01()
{MyArray<int> arr1(5); // 創建一個容量為5的數組for(int i=0;i<5;i++){arr1.Push_Back(i); // 向數組中添加元素}cout<<"arr1的打印輸出為:"<<endl;// MyArray<int> arr2(arr1); // 使用拷貝構造函數創建一個新數組// MyArray<int> arr3(100); // 使用賦值運算符進行賦值// arr3=arr1;printIntArray(arr1); // 打印數組內容cout<<"arr1的容量為:" << arr1.GetCapacity() << endl; // 打印數組容量 cout<<"arr1的大小為:" << arr1.GetSize() << endl; // 打印數組大小MyArray<int> arr2(arr1); // 使用拷貝構造函數創建一個新數組cout<<"arr2的打印輸出為:"<<endl;arr2.Pop_Back(); // 刪除數組的最后一個元素printIntArray(arr2); // 打印刪除后的數組內容cout<<"刪除一個元素后,arr2的大小為:" << arr2.GetSize() << endl; // 打印數組大小cout<<"刪除一個元素后,arr2的容量為:" << arr2.GetCapacity() << endl; // 打印數組容量}//測試自定義的數據類型class Person{public:Person() {}Person(string name,int age): m_Name(name),m_Age(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> arr3(10);Person p1("孫悟空",500);Person p2("豬八戒",300);Person p3("沙和尚",400);Person p4("唐僧",1000);Person p5("白龍馬",200);Person p6("小白龍",150);Person p7("小紅龍",120);arr3.Push_Back(p1);arr3.Push_Back(p2);arr3.Push_Back(p3);arr3.Push_Back(p4);arr3.Push_Back(p5);arr3.Push_Back(p6);arr3.Push_Back(p7); //打印數組printPersonArray(arr3); // 這里需要重載printIntArray函數來打印Person類型的數組}int main()
{test01(); // 測試函數cout << "------------------------" << endl;cout << "測試自定義數據類型的數組" << endl;cout << "------------------------" << endl;cout << "測試自定義數據類型的數組" << endl;test02(); // 測試函數return 0; // 返回0表示程序正常結束
}