C++類模板實戰(zhàn)之vector容器的實現(xiàn)
案例要求
可以對內(nèi)置數(shù)據(jù)類型以及自定義數(shù)據(jù)類型的數(shù)據(jù)進行存儲
將數(shù)組中的數(shù)據(jù)存儲到堆區(qū)
構(gòu)造函數(shù)中可以傳入數(shù)組的容量
提供對應(yīng)的拷貝構(gòu)造函數(shù)以及operator=防止淺拷貝問題
提供尾插法和尾刪法對數(shù)組中的數(shù)據(jù)進行增加和刪除
可以通過下標(biāo)的方式訪問數(shù)組中的元素
可以獲取數(shù)組中當(dāng)前元素個數(shù)和數(shù)組的容量
完成步驟
1、封裝數(shù)組類屬性并完成有參構(gòu)造以及析構(gòu)函數(shù)
#pragma once
#include<iostream>
using namespace std;
template<class T>
class Arrays
{
private:
T* arr;//數(shù)組arr存放T類型的數(shù)據(jù)
int capacity;//數(shù)組容量
int size;//數(shù)組大小
public:
Arrays(int capacity)
{
this->capacity = capacity;
this->size = 0;
this->arr = new T[this->capacity];
}
~Arrays()
{
if (this->arr != NULL)
{
delete []this->arr;
this->arr = NULL;
}
}
};我把自己的這個數(shù)組類模板放到一個.hpp文件里,方便測試的時候調(diào)用。代碼第一行是為了防止頭文件重復(fù)包含,template里面的T就是數(shù)組的數(shù)據(jù)類型,根據(jù)調(diào)用時不同的指定存放不同類型的數(shù)據(jù)。將數(shù)組arr以及數(shù)組容量和大小進行封裝,寫在私有權(quán)限下即可 。然后提供該類的有參構(gòu)造,參數(shù)列表傳入的是數(shù)組容量,有參構(gòu)造初始化了數(shù)組的容量以及大小并將數(shù)組開辟到了堆區(qū)。析構(gòu)函數(shù)就是來清理堆區(qū)數(shù)據(jù),如果我們開辟的堆區(qū)數(shù)組不為空,那就清理掉并將其指向NULL,這樣可以防止野指針出現(xiàn),避免異常。
2、提供對應(yīng)的深拷貝構(gòu)造函數(shù)防止調(diào)用析構(gòu)時出錯
Arrays(const Arrays& p)
{
this->capacity = p.capacity;
this->size = p.size;
this->arr = new T[p.capacity];
for (int i = 0; i < this->size; i++)
{
this->arr[i] = p.arr[i];
}
}
如果不提供深拷貝,那么編譯器就會有:this->arr=p->arr 這行代碼 ,那么一旦我們調(diào)用編譯器提供的淺拷貝,當(dāng)運行到析構(gòu)函數(shù)時,就會出現(xiàn)重復(fù)刪除地址的情況,必然會出現(xiàn)程序錯誤。所以我們要自己提供深拷貝構(gòu)造函數(shù),將上面的代碼改為 this->arr= new T[p.capacity] ,這樣調(diào)用析構(gòu)的時候各自刪除各的堆區(qū)數(shù)據(jù),不會出現(xiàn)上述情況。最后利用for循環(huán)將傳進來的對象的數(shù)據(jù)賦值給新開辟的數(shù)組。
3、重載類內(nèi)的賦值運算符防止淺拷貝問題出現(xiàn)
Arrays& operator=(const Arrays& p)
{
if (this->arr!=NULL)
{
delete []this->arr;
this->arr = NULL;
this->capacity = 0;
this->size = 0;
}
//深拷貝過程
this->capacity = p.capacity;
this->size = p.size;
this->arr = new T[this->capacity];
for (int i = 0; i < p.size; i++)
{
this->arr[i] = p.arr[i];
}
return *this;
}當(dāng)數(shù)組數(shù)據(jù)是對象的類型時,不能簡單的將數(shù)組進行賦值操作,因為也牽扯到直接賦值出現(xiàn)一樣的數(shù)組地址的情況,存在著深淺拷貝問題。賦值的時候是將傳入?yún)?shù)的數(shù)據(jù)賦值給自己,因此先把自己的屬性清空,然后就是深拷貝的實現(xiàn)了。最后返回的是*this,this指針能夠指向不同成員屬性,那么*this就是對象本身,然后看到返回值類型是對象引用,這樣就可以實現(xiàn)對象間的連續(xù)賦值了。
4、提供尾部插入和刪除的方法
void insert_Arrays(const T&value)
{
if (this->capacity == this->size)
{
return;
}
this->arr[size] = value;
this->size++;
}
void delete_Arrays()
{
if (this->size == 0)
{
return;
}
this->size--;
}尾插過程:先判斷數(shù)組是否已經(jīng)滿了,如果不滿就將形參賦值給當(dāng)前數(shù)組最后一個下標(biāo)的位置,然后更新數(shù)組下標(biāo),這樣就能保證每次插入的數(shù)據(jù)都在數(shù)組末尾。
尾刪的實現(xiàn):先判斷數(shù)組是否為空,不為空的時候直接把數(shù)組大小減一即可,讓編譯器訪問不到當(dāng)前的最后一個數(shù)組元素。注意尾刪的只是數(shù)據(jù)的指針,數(shù)組的地址并未刪除。
5、重載[]得到數(shù)組中對應(yīng)下標(biāo)的數(shù)據(jù)信息
T& operator[](int index)
{
return this->arr[index];
}
如果數(shù)組內(nèi)容是對象類型,是不存在對象數(shù)組的,所以要對[]運算符進行重載。返回值類型為數(shù)據(jù)類型的引用,也就是具體的數(shù)組內(nèi)的值,傳進去的整型參數(shù)就是數(shù)組下標(biāo)。
6、提供get方法獲取當(dāng)前數(shù)組容量及大小
int getSize()
{
return this->size;
}
int getCapacity()
{
return this->capacity;
}
這里就是經(jīng)典的get方法了,返回對應(yīng)封裝的成員屬性 ,不做多解釋。
7、提供打印函數(shù)測試基本數(shù)據(jù)類型和自定義數(shù)據(jù)類型的存儲
#include"arrays.hpp"
class Hero
{
friend void printHero(Arrays<Hero>&hero);
private:
string name;
string position;
public:
Hero() {}
Hero(string name, string position)
{
this->name = name;
this->position = position;
}
};
void printArrays(Arrays<int>arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
void printHero(Arrays<Hero>&hero)
{
for (int i = 0; i < hero.getSize(); i++)
{
cout << "姓名:"<<hero[i].name<<" 位置:"<<hero[i].position<<endl;
}
}
void test()
{
cout << "普通類型數(shù)組測試:" << endl;
cout << "輸入數(shù)組容量為:" ;
int n = 0; cin >> n;
Arrays<int> array(n);
cout << "輸入數(shù)據(jù):";
for (int i = 0; i < array.getCapacity(); i++)
{
int value = 0;
cin >> value;
array.insert_Arrays(value);
}
cout << "打印數(shù)組信息:"<<endl;
printArrays(array);
array.delete_Arrays();
cout << "刪除一次尾部數(shù)據(jù)后打印數(shù)組信息:" << endl;
printArrays(array);
}
void test1()
{
cout << "自定義類型數(shù)組測試:" << endl;
Hero h1("火舞","中單");
Hero h2("韓信","打野");
Hero h3("桑啟","游走");
Hero h4("守約","發(fā)育");
Hero h5("關(guān)羽","對抗");
Arrays<Hero> array(5);
array.insert_Arrays(h1);
array.insert_Arrays(h2);
array.insert_Arrays(h3);
array.insert_Arrays(h4);
array.insert_Arrays(h5);
printHero(array);
array.delete_Arrays();
cout << "刪除一次尾部數(shù)據(jù)后打印數(shù)組信息:"<<endl;
printHero(array);
}首先引入之前封裝的數(shù)組類頭文件,提供printArrays和printHero函數(shù)來進行數(shù)組信息的打印,test和test1函數(shù)分別是整型數(shù)組和對象數(shù)組的測試。接下來看運行效果。
運行效果:

到此這篇關(guān)于C++類模板實戰(zhàn)之vector容器的實現(xiàn)的文章就介紹到這了,更多相關(guān)C++ vector容器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
從c++標(biāo)準(zhǔn)庫指針萃取器談一下traits技法(推薦)
本篇文章基于gcc中標(biāo)準(zhǔn)庫源碼剖析一下標(biāo)準(zhǔn)庫中的模板類pointer_traits,并且以此為例理解一下traits技法,對c++ traits技法源碼分析感興趣的朋友跟隨小編一起看看吧2021-07-07
C++零基礎(chǔ)精通數(shù)據(jù)結(jié)構(gòu)之帶頭雙向循環(huán)鏈表
帶頭雙向循環(huán)鏈表:結(jié)構(gòu)最復(fù)雜,一般用在單獨存儲數(shù)據(jù)。實際中使用的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表。另外這個結(jié)構(gòu)雖然結(jié)構(gòu)復(fù)雜,但是使用代碼實現(xiàn)以后會發(fā)現(xiàn)結(jié)構(gòu)會帶來很多優(yōu)勢,實現(xiàn)反而簡單2022-03-03

