有關模板類----實現Vector的類模板
由上一篇的文章中 ,我們已經知道,模板是一個程式碼生成器,可以極大效率提高我們的工作效率,實現讓編譯器為我們產生程式碼的機制
在C++面向物件中,我們在對類的使用上,已經達到了最少80%了,因此,模板類的使用,將極大的提高程式的執行效率,節省程式的執行時間。
(一)概念區分
類模板:也稱類屬類或類生產類,允許使用者為類定義一種模式,使得類中的某些資料成員,默寫成員函式的引數,某些成員引數的返回值,能夠取任意型別(包括系統預定義和使用者自定義),如果一個類中資料成員的資料型別不能確定,或者是某個成員函式的引數返回值的型別不能確定,就必須將此類宣告為模板,他的存在不是代表一個具體的,實際的類,而是代表一類類。
類模板由三種類型的模板引數:型別模板引數,非型別模板引數和模板的模板引數。
模板類:是類模板例項化的的一個產物,可以從類模板派生出新的類,既可以派生類模板,也可以派生非類模板,模板類的重點是類表示由一個模板生成而來的類,模板類與平臺無關,具有可移植性,可用於基本資料型別,可用來建立動態增長和減小的資料結構。
模板類的例項化:只要有一種不同的型別,編譯器就會例項化出一個對應的類。
(二)有關Vector模板的實現
Vector:是用來連續的儲存資料的,類似於順序表,在其中任意位置的插入或者刪除的效率比較低,但是對記憶體碎片存在的就比較少,在某些情況下,對記憶體的使用率比較好。
由上面可以看出,由於在模板中對於輸出運算子的過載,存在著一定的問題,因此上面對於String型別與內建型別分別測試。#define _CRT_SECURE_NO_WARNINGS 1 //注:memcpy會出現淺拷貝的問題,因此在拷貝元素時,應該慎用 #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string> #include<assert.h> using namespace std; template<typename T> class Vector { public: Vector()//建構函式,順序表為空 :_start(0) , _finish(0) , _endOfStorage(0) {} Vector(const T*arr, size_t size);//宣告,順序表中已經存放元素 Vector(const Vector& t) //拷貝建構函式 { size_t size = t.Size(); _start = new T[size]; for (size_t i = 0; i < size; ++i) { _start[i] = t._start[i]; } _finish = _start + size; _endOfStorage = _finish; } Vector<T>&operator=(const Vector<T>&v)//賦值運算子的過載 { if (this != &v) { size_t size = v.Size(); _start = new T[size]; for (size_t i = 0; i < size; ++i) { _start[i] = v._start[i]; } } return*this; } void PushBack(const T& data)//尾插,注意在此處,const修飾的是data { CheckCapacity(); *_finish++ = data;//改變_finish的位置,從而將資料插入在上面 } void PopBack()//尾刪,直接改變順序表中_finish的位置 { --_finish; } void Insert(size_t pos, const T& data)//任意位置的插入 { //檢查pos是否合法 assert(pos < Size());//檢查當前插入的位置是否有效 CheckCapacity(); CheckCapacity(); size_t i = 0; //搬移元素 for (i = Size(); i > pos; --i) { _start[i] = _start[i - 1]; } _start[pos] = data; ++_finish; } void Erase(size_t pos)//任意位置刪除 { assert(pos < Size()); size_t i = 0; for (i = pos; i < Size() - 1; ++i)//減1的原因是:防止拿到最大元素處的後一個元素 { _start[i] = _start[i + 1]; } --_finish; } size_t Size()const//元素的個數 { return _finish - _start; } size_t Capacity()const//容量 { return _endOfStorage - _start; } bool Empty()const//判斷順序表是否為空 { return (Size() == 0);//_start==_finish; } void Resize(size_t newSize, const T& data = T())//將順序表中的size改變到newSize { size_t OldSize = Size();//將順序表中的size做一個記錄,從而方便下面的比較 size_t capacity = Capacity(); if (newSize < OldSize) { _finish = _start + newSize;//改變裡面儲存空間的大小 } else if ((OldSize < newSize) && (newSize < capacity)) { for (size_t i = OldSize; i < newSize; ++i)//將需要拷貝的資料拷貝下來 { _start[i] = data; } _finish = _start + newSize; } else//此種情況為,新的順序表的大小,比原來順序表中的空間都大,因此需要開闢新的空間 { T*tmp = new T[newSize]; for (size_t i = 0; i < OldSize; ++i)//先拷貝舊空間的元素 { tmp[i] = _start[i]; } for (size_t j = OldSize; j < newSize; ++j)//將新的元素填充剩下的這段空間 { tmp[j] = data; } delete[]_start; _start = tmp; _finish = _start + newSize; _endOfStorage = _start + newSize; } } T& operator[](size_t index)//下標運算子過載(成對出現)隨機訪問 { return _start[index]; } const T& operator[](size_t index)const { return _start[index]; } T& Front()//返回最開始的元素 { return *_start;//_start表示指向首元素的指標,對其解引用表示取出首地址的內容 } const T& Front()const { return *_start; } T& Back() { return *(_finish - 1);//同Front } const T& Back()const { return *(_finish - 1); } void Clear()//置空順序表 { _finish = _start; } template<class T>//不是類的成員函式 friend ostream&operator<<(ostream&_cout, const Vector<T>&t)//輸出運算子過載 { for (size_t i = 0; i < t.Size(); ++i) { _cout << t[i] << " "; } //memcpy(_Start, t._start, sizeof(t)); return _cout; } void Display() { size_t size = Size(); for (size_t i = 0; i < size; ++i) { cout << _start[i]; cout << " "; } cout << endl; } ~Vector()//解構函式 { if (_start != NULL) { delete[]_start; _start = NULL; _finish = NULL; _endOfStorage = NULL; } } private: void CheckCapacity() { size_t size = Size(); size_t capacity = Capacity(); if (size >= capacity) { size_t newCapacity = capacity * 2 + 3; //申請新空間 T*_tmp = new T[newCapacity]; //拷貝元素 for (size_t i = 0; i < size; ++i) { _tmp[i] = _start[i]; } //釋放舊空間 if (_start)//防止釋放的空間為空,從而導致程式崩潰 delete[] _start; _start = _tmp; _finish = _start + size; _endOfStorage = _start + newCapacity; } } private: T*_start; //表示順序的開始,空間起始位置 T*_finish; //表示順序表中儲存元素的多少 T*_endOfStorage; //表示順序表的容量 }; template<typename T> Vector<T>::Vector(const T*arr, size_t size)//有元素,1、開闢大小 2、複製資料 :_start(new T[size]) , _finish(_start + size) , _endOfStorage(_start + size) { //memcpy(_start, arr, sizeof(T)*size)//會存在淺拷貝的問題 for (size_t i = 0; i < size; ++i)//拷貝元素 { _start[i] = arr[i]; } } class String { public: String(const char* pStr = "") { if (_pStr == NULL) { _pStr = new char[1]; (*_pStr) = '\0'; } else { _pStr = new char[strlen(pStr) + 1]; strcpy(_pStr, pStr); } } /*String(const String &s)//拷貝建構函式 :_pStr(NULL) { String tmp(s._pStr); swap(_pStr, tmp); }*/ String(const String &s) :_pStr(new char[strlen(s._pStr) + 1]) { strcpy(_pStr, s._pStr); } String& operator=(const String&s) { if (this != &s)//檢測是不是自己給自己賦值 { char*tmp = new char[strlen(s._pStr) + 1]; strcpy(tmp, s._pStr); delete[] _pStr; _pStr = NULL; _pStr = tmp; } return *this; } friend ostream&operator<<(ostream&_cout, const String&t)//輸出運算子過載 { _cout << t._pStr; return _cout; } ~String() { if (_pStr != NULL) { delete[] _pStr; _pStr = NULL; } } private: char*_pStr; }; #if 0 void FunTest1() { //Vector<int> s1; int arr[] = { 1, 2, 3, 4 }; Vector<int> s2(arr, sizeof(arr) / sizeof(arr[0])); //Vector<int> s3(s2); //cout << s2 << endl; //s1 = s2; //cout << s1 << endl; cout << "size= " << s2.Size() << endl; cout << "capacity= " << s2.Capacity() << endl; cout << s2 << endl; s2.Display(); s2.PushBack(5); s2.PushBack(6); s2.PushBack(7); cout << "size= " << s2.Size() << endl; cout << "capacity= " << s2.Capacity() << endl; cout << s2 << endl; s2.Display(); s2.PopBack(); s2.PopBack(); cout << "size= " << s2.Size() << endl; cout << "capacity= " << s2.Capacity() << endl; cout << s2 << endl; s2.Display(); s2.Erase(2); cout << "size= " << s2.Size() << endl; cout << "capacity= " << s2.Capacity() << endl; s2.Insert(3,7); cout << "size= " << s2.Size() << endl; cout << "capacity= " << s2.Capacity() << endl; cout << s2 << endl; s2.Display(); s2.Resize(4); cout << "size= " << s2.Size() << endl; cout << "capacity= " << s2.Capacity() << endl; s2.Display(); s2.Resize(30); cout << "size= " << s2.Size() << endl; cout << "capacity= " << s2.Capacity() << endl; cout << s2 << endl; s2.Display(); } #endif void FunTestString() { Vector<String> s; s.PushBack("1111"); s.PushBack("2222"); s.PushBack("3333"); cout << "size= " << s.Size() << endl; cout << "capacity= " << s.Capacity() << endl; cout << s << endl; s.PushBack("4444"); cout << "size= " << s.Size() << endl; cout << "capacity= " << s.Capacity() << endl; cout << s << endl; s.PopBack(); cout << "size= " << s.Size() << endl; cout << "capacity= " << s.Capacity() << endl; cout << s << endl; s.Insert(2, "5555"); cout << "size= " << s.Size() << endl; cout << "capacity= " << s.Capacity() << endl; cout << s << endl; s.Resize(4); cout << "size= " << s.Size() << endl; cout << "capacity= " << s.Capacity() << endl; cout << s << endl; s.Resize(20,"0000"); cout << "size= " << s.Size() << endl; cout << "capacity= " << s.Capacity() << endl; cout << s << endl; s.Clear(); cout << "size= " << s.Size() << endl; cout << "capacity= " << s.Capacity() << endl; cout << s << endl; } int main() { FunTestString(); system("pause"); return 0; }
結果如下:
String型別
內建型別:
相關推薦
有關模板類----實現Vector的類模板
由上一篇的文章中 ,我們已經知道,模板是一個程式碼生成器,可以極大效率提高我們的工作效率,實現讓編譯器為我們產生程式碼的機制 在C++面向物件中,我們在對類的使用上,已經達到了最少80%了,因此,模板類的使用,將極大的提高程式的執行效率,節省程式的執行時間。 (一)概念區分
子類實現父類的抽象方法,父類呼叫抽象方法
首先,父類有一個抽象方法,並且在自身的其他方法中呼叫了 public abstract class Baba { public abstract void say(String a); public void dosomething(String a){ say(a); }
動態記憶體管理allocator類C++ STL標準模板庫vector實現
//vector.h #ifndef NSTL_VECTOR_H_ #define NSTL_VECTOR_H_ #include <memory> #include <string> namespace nstl { class vector { public
c++中模板的實現(模板類和模板函數)
c++ 模板實例化 泛型編程 [TOC] 模板 當我們實現一個交換函數時,我們可以寫成如下。 void Swap(int& x, int& y) { int tmp = x; x = y; y = tmp; } 這裏只能交換兩個整
後臺開發閱讀筆記——STL(標準模板庫)的使用之string類實現
string類的實現: class String { public: String(const char *str=null); String(const String &other); ~String(); String &operator =(const
C++模板類實現hashMap
非常常見的hashMap,具體介紹可以自己百度,這裡就不詳細介紹了 主要採用的是拉鍊法,然後hash函式採用的是C++自帶的hash函式庫 標頭檔案 1 #ifndef MAP_H 2 #define MAP_H 3 4 // Hash table impl
二叉堆類模板的實現以及使用它進行堆排序
二叉堆:二叉堆一棵完全二叉樹,從遞迴的定義來講,對於完全二叉樹的任何一個節點,其左孩子要麼是空樹要麼是一個完全二叉樹,右孩子同上。 堆:對於一個堆來講,可以是一個大根堆,也可以是一個小根堆。 大根堆的性質:對於在大根堆任何一個節點,其值不小於左右孩子的值。 小根堆的性質:對於在大
BST(二叉搜尋/排序樹)類模板的實現
BST樹的遞迴定義: (1)BST樹是一棵空樹。 (2)BST樹由根節點、左子樹和右子樹。左子樹和右子樹分別都是一棵BST樹。 由於二叉樹的遞迴定義,使得在二叉樹中許多操作中可以以遞迴的方式書寫操作,程式碼更加淺顯易懂。 重點條件:左子樹中的所有節點的資料域都小於或等於根節點的資
STL典型使用--vector類模板
vector是將元素放在一個動態陣列中加以管理的容器,vector可以隨機存取元素(用[]操作符或at()直接存取),也支援迭代器存取元素;vector在尾部新增或移除元素十分高效,但是在中間或者頭部插入/移除元素會比較費時。 1. 增加/刪除vector內的元
資料庫配置excel匯出模板,poi匯出工具類實現過程
1.配置模板id,檔名字尾,本地儲存位置 2.配置模板表頭,資料位於表格的列號,對應實體的欄位,型別 3.儲存匯出的記錄,參考頁面欄位設計 4.後端呼叫部分設計參考 箭頭標明泛型匯出實體類T,匯出工具類例項化,執行緒排程 5.工具類主要設計 表頭資料查詢並寫入表頭 6.資料庫查詢
C++模板的實現(模板函式和模板類,附帶模板實現順序表和連結串列程式碼)
模板 當我們實現一個交換函式時,我們可以寫成如下。 void Swap(int& x, int& y) { int tmp = x; x = y; y = tmp; } 這裡只能交換兩個整數,當我們
用c++實現 c++單鏈表的實現(採用模板類)
函式實現資料的插入(頭插&&尾插)、刪除(頭刪&&尾刪)、查詢、按值插入、按值刪除、求長、單鏈表清除、單鏈表摧毀、資料的逆置以及資料排序 main函式 #include"List.h"//單鏈表 void main() { List&l
二叉樹的模板類實現
二叉樹的定義 二叉樹(Binary Tree)是n>0個結點的有限集合,該集合或者為空集(稱為空二叉樹),或者由一個根節點和兩棵不相交的分別被稱為左子樹和右子樹組成。 ·不存在度大於2的結點; ·左右子樹是有序的,次序不能任意的顛倒。 二叉樹的
類模板---求陣列的最大值 找出一個數組中的元素的最大值,陣列大小為10。(用類模板來實現) 陣列元素型別作為類模板的引數。 在下面的程式段基礎上完成設計,只提交begin到end部
#include <iostream> #include <string> using namespace std; template <class T> class Array_max //宣告類模板 {
自己動手寫資料結構:二叉樹BinaryTree類模板C++實現(功能較全)
#ifndef MYBINARYTREE_H #define MYBINARYTREE_H template <class T> class BinaryTree { protected: struct TNode { T val; TNode*
C++中用模板類(結點類,連結串列類)實現的單鏈表的合併操作!
程式碼通俗易通,如下 List.h #include<stdio.h> template <class T> class ListNode { T data; ListNode<T>* link; public:
棧與佇列-順序棧與鏈棧類模板的實現(資料結構基礎 第3周)
這是用C++編寫的棧的類模板的實現,包括順序棧和鏈棧,並進行了簡單的測試。 程式碼中srrStack類和lnkStack類均繼承於Stack類, Stack類可以看成是棧的邏輯結構(ADT抽象資料型別,Abstract Data Type)。注意這裡實現是棧與
簡單的C++委託 —— 用模板類實現類成員函式的回撥
template <class R, class P1, class P2>class IDelegate{public:virtual R Invoke(P1, P2) = 0;};template <class T, class R, class P1, class P2>clas
c++:利用模板類實現氣泡排序
首先我們來明確函式模板與類模板的概念及其用法。 模板是一種對型別進行引數化的工具,通常有兩種形式------>函式模板和類模板。 函式模板針對僅引數型別不同的函式; 類模板針對僅資料成員和成員函式型別不同的類。 函式模板的格式: template &l
資料結構——迴圈佇列(順序佇列)模板類實現
資料結構筆記3.3 順序佇列是用順序表實現的(即依託於陣列),這裡實現的是迴圈佇列,其實也可以不用迴圈,但是那樣的話,空間的利用效率就太低了,這就是”假溢位”問題,因為在陣列的前端可能還有空閒的位置(因為佇列中的資料是在動態變化的,可能出隊也可能入對)