目录
本文仅对模板的一些概念及基本用法做总结供初学者参考及复习,大神勿喷......
模板
what
对于重载机制而言,C++能够通过函数的不同参数以及所属类不同正确调用重载函数。
但当面对重载函数只有参数类型不同,其他代码都相同时,需要一种机制增强它的复用性,使得变量类型也参数化,因而引入模板。
可以理解为定义一个公共的需求,比如word文档的模板,定义了大家都有可能用到的样式,C++的模板也就是定义一个公共的模块,把一些类似的功能的模块归类为一个模板,
why
当遇到代码相同,参数变量类型不同的场景时,为了增强代码的复用和扩展性,减少了代码的冗余。
how
基本语法:
- 函数模板
Template <class或者也可以用typename T>
返回类型 函数名(形参表)
{//函数定义体 }
- 类模板
template < class或者也可以用typename T >
class类名{
//类定义......
};
使用注意:
- 模板传入的具体类型在编译时无法确定,在调用时才确定其类型;
- 编译器从函数模板通过具体类型产生不同的函数;编译器会对函数模板进行两次编译:在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译,具体参考:https://blog.csdn.net/qq_39108291/article/details/102019805?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control
- 其作用域仅限模板声明下方的函数或类,在模板声明与函数或类之间尽可能不要加代码;
- 对于模板类,只要定义类时用到了模板,下面调用的时候一定要用<>,传入具体类型,如果不确定具体类型,再套入一个模板类型。
附一段可以指定规则排序任意类型数组的简单冒泡排序及测试代码:
#include <iostream>
using namespace std;
bool Rule(int a,int b)
{
return a%3;
}
bool Rule1(int a,int b)
{
return a<b;
}
template <typename T>
void BubbleSort(T* arr,int n,bool (*pfn)(T,T))
{
for(int i = 0; i < n-1; i++)
{
for(int j = 0; j < n-1-i; j++)
{
if((*pfn)(arr[j],arr[j+1]))
{
T temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
int main()
{
int arr[] = {3,8,0,4,1,2,5,9,7,6};
BubbleSort(arr,sizeof(arr)/sizeof(arr[0]),&Rule);
for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
cout<<arr[i]<<" ";
cout<<endl;
BubbleSort(arr,sizeof(arr)/sizeof(arr[0]),&Rule1);
for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
cout<<arr[i]<<" ";
cout<<endl;
system("pause");
return 0;
}
运行结果:
封装的简单的模板链表类代码如下(使用尾插法、头删除):
#include <iostream>
using namespace std;
template <typename T>
class CList
{
private:
struct Node{
T val;
Node* pNext;
};
Node* m_pHead; //头指针
Node* m_pTail; //尾指针
int m_nLength; //链表长
public:
CList()
{
m_pHead = nullptr;
m_pTail = nullptr;
m_nLength = 0;
}
//CList(int count,T val = 0) //通过构造函数构造一个链表
//{
// m_pHead = nullptr;
// m_pTail = nullptr;
// m_nLength = 0;
// for(int i = 0; i < count; i++)
// Push_Back(val);
//}
~CList()
{
while(m_pHead)
Pop_Front();
}
public:
void Push_Back(T val)
{
//初始化一个节点
Node* node = new Node;
node->val = val;
node->pNext = nullptr;
//插入到链表尾部
if(!m_pHead)
{
m_pHead = node;
m_pTail = node;
}
else
{
m_pTail->pNext = node;
m_pTail = node;
}
m_nLength++;
}
void Pop_Front()
{
//链表中没有节点
if(!m_pHead)
return;
//有一个节点
if(m_pHead == m_pTail)
{
delete m_pHead;
m_pHead = nullptr;
m_pTail = nullptr;
m_nLength = 0;
return ;
}
//有多个节点
Node* pDel = m_pHead;
m_pHead = m_pHead->pNext;
delete pDel;
pDel = nullptr;
m_nLength--;
}
void Traverse()
{
Node* pTemp = m_pHead;
while(pTemp)
{
cout<<pTemp->val<<" ";
pTemp = pTemp->pNext;
}
cout<<"链表长度为"<<m_nLength<<endl;
}
};
int main()
{
CList<int> list;
for(int i = 0; i < 10; i++)
list.Push_Back(i);
list.Pop_Front();
list.Traverse();
CList<double> list_d;
list_d.Push_Back(1.1);
list_d.Push_Back(1.2);
list_d.Push_Back(1.3);
list_d.Traverse();
CList<char> list_c;
list_c.Push_Back('a');
list_c.Push_Back('b');
list_c.Traverse();
system("pause");
return 0;
}
运行结果: