[TOC]
專業(yè)從事成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、成都外貿(mào)網(wǎng)站建設(shè)公司,高端網(wǎng)站制作設(shè)計(jì),微信平臺(tái)小程序開發(fā),網(wǎng)站推廣的成都做網(wǎng)站的公司。優(yōu)秀技術(shù)團(tuán)隊(duì)竭力真誠服務(wù),采用H5技術(shù)+CSS3前端渲染技術(shù),響應(yīng)式網(wǎng)站建設(shè),讓網(wǎng)站在手機(jī)、平板、PC、微信下都能呈現(xiàn)。建站過程建立專項(xiàng)小組,與您實(shí)時(shí)在線互動(dòng),隨時(shí)提供解決方案,暢聊想法和感受。當(dāng)我們實(shí)現(xiàn)一個(gè)交換函數(shù)時(shí),我們可以寫成如下。
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
這里只能交換兩個(gè)整數(shù),當(dāng)我們一會(huì)需要實(shí)現(xiàn)兩個(gè)字符交換時(shí),我們有需要重新寫個(gè)函數(shù),然而兩份代碼有很多相同的部分,這樣是不是很麻煩。假如我們只需要寫一份代碼便可以實(shí)現(xiàn)不同類型的交換,是不是很棒。是的,這個(gè)編譯器已經(jīng)幫我們?cè)O(shè)計(jì)好了,這就是所謂的泛型編程。
模板是泛型編程的基礎(chǔ),所謂泛型編程就是編寫與類型無關(guān)的邏輯代碼,是一種復(fù)用的方式。模板分為模板函數(shù)和模板類。
template< class 形參名1, class 形參名2, class 形參名n>
返回類型 函數(shù)名(參數(shù)列表)
{...}模板形參的定義既可以使用class,也可以使用typename,含義是相同的。
剛剛的Swap函數(shù)就可以用模板函數(shù)搞定了。
template<class T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
看看是不是可以進(jìn)行多種類型交換,測(cè)試結(jié)果:
這就是模板函數(shù)的實(shí)現(xiàn),當(dāng)然我們很好奇為什么一個(gè)函數(shù)就可以搞定。其實(shí)在底層實(shí)現(xiàn)了函數(shù)重載,我們轉(zhuǎn)到匯編代碼便可得知。
int main()
{
00394D30 push ebp
00394D31 mov ebp,esp
00394D33 sub esp,114h
00394D39 push ebx
00394D3A push esi
00394D3B push edi
00394D3C lea edi,[ebp-114h]
00394D42 mov ecx,45h
00394D47 mov eax,0CCCCCCCCh
00394D4C rep stos dword ptr es:[edi]
00394D4E mov eax,dword ptr [__security_cookie (039A000h)]
00394D53 xor eax,ebp
00394D55 mov dword ptr [ebp-4],eax
int a1 = 1, a2 = 2;
00394D58 mov dword ptr [a1],1
00394D5F mov dword ptr [a2],2
Swap(a1, a2);
00394D66 lea eax,[a2]
00394D69 push eax
00394D6A lea ecx,[a1]
00394D6D push ecx
00394D6E call Swap<int> (039137Ah)
00394D73 add esp,8
char c1 = 5, c2 = 6;
00394D76 mov byte ptr [c1],5
00394D7A mov byte ptr [c2],6
Swap(c1, c2);
00394D7E lea eax,[c2]
00394D81 push eax
00394D82 lea ecx,[c1]
00394D85 push ecx
00394D86 call Swap<char> (0391375h)
00394D8B add esp,8
double d1 = 1.222, d2 = 2.011111111111;
00394D8E movsd xmm0,mmword ptr [__real@3ff38d4fdf3b645a (0397BD0h)]
00394D96 movsd mmword ptr [d1],xmm0
00394D9B movsd xmm0,mmword ptr [__real@400016c16c16c072 (0397BD8h)]
00394DA3 movsd mmword ptr [d2],xmm0
Swap(d1, d2);
00394DA8 lea eax,[d2]
00394DAB push eax
00394DAC lea ecx,[d1]
00394DAF push ecx
00394DB0 call Swap<double> (039137Fh)
00394DB5 add esp,8
return 0;
00394DB8 xor eax,eax
}
可以看到在底層,每一次調(diào)用Swap函數(shù)都會(huì)建立一個(gè)棧幀,而每次棧幀建立,形參的類型是不同的,建立棧幀也是不同的。當(dāng)我們使用模板時(shí)編譯器會(huì)進(jìn)行一個(gè)推演的過程,這個(gè)過程在編譯之前進(jìn)行。推演時(shí),編譯器會(huì)根據(jù)傳遞參數(shù)的類型實(shí)例化(編譯器隱式實(shí)例化
)
出相應(yīng)的函數(shù),在進(jìn)行編譯。例如:
但是當(dāng)我們遇到這樣Swap(1,1.2302102);
,此時(shí)編譯器如何判斷到底實(shí)例化成那種類型?
其實(shí)我們?nèi)绻涯0迓暶鳛檫@樣既可以解決了。模板函數(shù)重載
(與上面的函數(shù)構(gòu)成重載)
template<typename T1 ,class T2> //使用class 和 typename一樣的效果
void Swap(T1& x,T2& y)
{
T1 tmp = x;
x = y;
y = tmp;
}
有時(shí)候我們可能會(huì)要到這樣的奇葩問題。
template< class T>
const T Add(T& x,T& y)
{
return x+y;
}
當(dāng)我們這樣調(diào)用時(shí)Add(1,5.222222);
,編譯器又該如何實(shí)例化呢?
這就涉及必須顯示指定實(shí)例化類型 模板參數(shù)顯示實(shí)例化
Add<double>
(1.5.2222222); 這樣就可以搞定剛剛的問題。
template<class 形參名1, class 形參名2, ...class 形參名n>
class 類名
{ ... };
當(dāng)我們剛開始用c++寫順序表和鏈表之前,我們是這樣的。
typedef int Datatype;
typedef struct SeqList
{
struct SeqList* _data;
size_t _size;
}SeqList;
typedef struct ListNode
{
struct ListNode* _prev;
struct ListNode* _next;
Datatype _data;
}ListNode;
我們這樣定義順序表和鏈表的,但是會(huì)存在很大一個(gè)問題,如下。
當(dāng)我們?cè)谝粋€(gè)程序中要使用兩個(gè)不同數(shù)據(jù)類型順序表和鏈表,這樣是無法完成的,除非我們每種類型定義一個(gè)類型
typedef int Datatype; //存int類型
typedef struct SeqList
{
struct SeqList* _data;
size_t _size;
}SeqList;
typedef struct ListNode
{
struct ListNode _prev;
struct ListNode _next;
Datatype _data;
}ListNode;
typedef char Datatype; //存char類型
typedef struct SeqList
{
struct SeqList* _data;
size_t _size;
}SeqList;
typedef struct ListNode
{
struct ListNode* _prev;
struct ListNode* _next;
Datatype _data;
}ListNode;
這樣就會(huì)很麻煩,在我們學(xué)了模板之后,我們可以這樣。
模板實(shí)現(xiàn)順序表
template<class T>
class Vector
{
public:
Vector():_first(NULL),_finish(NULL),_endofstorge(NULL)//構(gòu)造函數(shù)
{}
~Vector()//析構(gòu)函數(shù)
{
delete[]_first;
_first = _finish = _endofstorge = NULL;
}
Vector(const Vector<T>& v)//拷貝構(gòu)造
:_first(NULL)
,_finish(NULL)
,_endofstorge(NULL)
{
int len = v._finish - v._first;
_first = _finish = new T[len];
T* start = v._first;
while(start != v._finish)
{
*(_finish) = *start;
++_finish;
++start;
}
_endofstorge = _first+len;
}
Vector<T>& operator=(Vector<T>& v) //賦值運(yùn)算符重載
{
delete[]_first;
Vector<T> v1(v);
swap(_first ,v1._first);
swap(_finish , v1._finish);
swap(_endofstorge , v1._endofstorge);
return *this;
}
void PushBack(const T& x) //尾插
{
if(_finish == _endofstorge)
Expand(Capacity()*2+1);
_first[Size()] = x;
++_finish;
}
void PopBack()//尾刪
{
Erase(Size()-1);
}
void Expand(size_t n) //擴(kuò)容
{
int size = Size();
if(n>Capacity())
{
T* tmp = new T[n];
for (int i = 0;i<size;i++)
{
*(tmp+i) = *(_first+i);
}
delete[]_first;
_first = tmp;
_finish = _first + size;
_endofstorge = _first + n;
}
}
void Insert(size_t pos,const T& x)//隨機(jī)插入
{
assert(_first+pos <= _finish);
if(_finish == _endofstorge)
Expand(2*Capacity());
T* end = _finish;
while(end != _first + pos)
{
*(end) = *(end-1);
--end;
}
_first[pos] = x;
++_finish;
}
void Erase(size_t pos)//刪除任意位置的數(shù)據(jù)
{
assert(_first+pos < _finish);
int size = Size();
T* start = _first + pos + 1;
while(start != _finish)
{
*(start - 1) = *(start);
++start;
}
--_finish;
}
size_t Find(const T& x)//查找
{
int size = Size();
for(int i = 0;i<size;i++)
{
if (_first[i] == x)
return i;
}
return -1;
}
T& operator[](size_t pos)//獲取任意位置的數(shù)據(jù)
{
assert(pos<Size());
return _first[pos];
}
const T& operator[](size_t pos) const
{
assert(_first+pos < _finish);
return _first[pos];
}
size_t Size() //求取順序表的有效容量
{
return _finish - _first;
}
size_t Capacity()//求取順序表的容量
{
return _endofstorge - _first;
}
bool Empty() //判斷是否為空順序表
{
return Size()==0;
}
protected:
T* _first;
T* _finish;
T* _endofstorge;
};
測(cè)試代碼及結(jié)果:
void VectorTest()
{
Vector<int> v;
v.PushBack(1);
v.PushBack(2);
v.PushBack(3);
v.PushBack(4);
v.PushBack(5);
v.PushBack(6);
v.PushBack(7);
PrintVocter(v);
Vector<string> v1;
v1.PushBack("hello");
v1.PushBack("world !");
v1.PushBack("i");
v1.PushBack("love");
v1.PushBack("you");
PrintVocter(v1);
}
模板實(shí)現(xiàn)雙鏈表
#ifndef __LIST_H__
#define __LIST_H__
#include<string>
#include<iostream>
using namespace std;
template <class T>
struct ListNode
{
struct ListNode* _prev;
struct ListNode* _next;
T _data;
};
template <class T>
class List
{
typedef ListNode<T> Node;
public:
List()//構(gòu)造函數(shù)
{
_head = new Node;
_head->_next = _head->_prev = _head;
}
List(const List<T>& h) //拷貝構(gòu)造
{
Node* head = h._head;
Node* tmp = head->_next;
_head = new Node;
_head->_next = _head->_prev = _head;
while (tmp != head)
{
PushBack(tmp->_data);
tmp = tmp->_next;
}
}
~List() //析構(gòu)函數(shù)
{
Clear();
delete _head;
_head = NULL;
}
void PushBack(const T& x) //尾插
{
Node *tmp = new Node;
tmp->_data = x;
Node* tail = _head->_prev;
tail->_next = tmp;
tmp->_prev = tail;
_head->_prev = tmp;
tmp->_next = _head;
}
void PushFront(const T& x) //頭插
{
Node *tmp = new Node;
tmp->_data = x;
Node* cur = _head->_next;
tmp->_prev = _head;
_head->_next = tmp;
tmp->_next = cur;
cur->_prev = tmp;
}
void PopBack() //尾刪
{
Node* cur = _head->_prev;
_head->_prev = cur->_prev;
cur->_prev->_next = _head;
delete[]cur;
cur->_next = cur->_prev = NULL;
}
void PopFront() //頭刪
{
Node* cur = _head->_next;
_head->_next = cur->_next;
cur->_next->_prev = _head;
}
void Insert(Node* pos,const T& x) //隨機(jī)插入
{
Node* cur = new Node;
cur->_data = x;
cur->_prev = pos->_prev;
pos->_prev->_next = cur;
pos->_prev = cur;
cur->_next = pos;
}
void Erase(Node* pos) //刪除隨機(jī)位置
{
Node* cur = pos->_next;
pos->_prev->_next = cur->_next;
cur->_next->_prev = pos->_prev;
}
void Clear() //清除鏈表數(shù)據(jù)
{
Node* cur = _head->_next;
while(cur != _head)
{
Node* tmp = cur;
cur = cur->_next;
delete tmp;
}
_head->_next = _head;
_head->_prev = _head;
}
Node* Find(const T& x) //查找
{
Node* cur = _head->_next;
while (cur != _head)
{
if(cur->_data==x)
return cur;
cur = cur->_next;
}
return NULL;
}
size_t Size() //求取鏈表長度
{
size_t count = 0;
Node* cur = _head->_next;
while (cur != _head)
{
count++;
cur = cur->_next;
}
return count;
}
bool Empty()
{
if (_head->_next = _head->_prev)
return 1;
return 0;
}
void PrintList() //打印鏈表
{
Node* tmp = _head->_next;
while (tmp != _head)
{
std::cout<<tmp->_data<<" ";
tmp = tmp->_next;
}
std::cout<<std::endl;
}
protected:
Node* _head;
};
#endif//__LIST_H__
這樣我們的順序表和鏈表就可以實(shí)現(xiàn)任意類型的程序了。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
當(dāng)前文章:c++中模板的實(shí)現(xiàn)(模板類和模板函數(shù))-創(chuàng)新互聯(lián)
文章URL:http://bm7419.com/article36/ijisg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、網(wǎng)站建設(shè)、手機(jī)網(wǎng)站建設(shè)、網(wǎng)站導(dǎo)航、定制開發(fā)、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容