目录
一、模板函数
1.一般模板函数
数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计。它的最大特点是把函数使用的数据类型作为参数。
函数模板的声明形式为:
template<typename 数据类型参数标识符>
<返回类型><函数名>(参数表)
{ 函数体 }
其中,template是定义模板函数的关键字;template后面的尖括号不能省略;typename(或class)是声明数据类型参数标识符的关键字,用以说明它后面的标识符是数据类型标识符。这样,在以后定义的这个函数中,凡希望根据实参数据类型来确定数据类型的变量,都可以用数据类型参数标识符来说明,从而使这个变量可以适应不同的数据类型。函数模板只是声明了一个函数的描述即模板,不是一个可以直接执行的函数,只有根据实际情况用实参的数据类型代替类型参数标识符之后,才能产生真正的函数。
函数模板的数据类型参数标识符实际上是一个类型形参,在使用函数模板时,要将这个形参实例化为确定的数据类型。将类型形参实例化的参数称为模板实参,用模板实参实例化的函数称为模板函数。模板函数的生成就是将函数模板的类型形参实例化的过程。
Tips:
1.函数模板允许使用多个类型参数,但在template定义部分的每个形参前必须有关键字typename或class,即:
template<class 数据类型参数标识符1,…,class 数据类型参数标识符n>
<返回类型><函数名>(参数表)
{ 函数体 }
2.在template语句与函数模板定义语句<返回类型>之间不允许有别的语句。
如下面的声明是错误的:
template<class T>
int I;
T min(T x,T y)
{ 函数体 }
3.模板函数类似于重载函数,但两者有很大区别:函数重载时,每个函数体内可以执行不同的动作,但同一个函数模板实例化后的模板函数都必须执行相同的动作。
2.特化模板函数
使用模板时会遇到一些特殊的类型需要特殊处理,不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板函数(就是写出一个模板函数专门给该类型使用)
使用模板特化时,必须要先有基础的模板函数(就是上面第一个模板函数)
使用特化模板函数时格式有要求:
1.template 后直接跟<> 里面不用写类型
2.函数名<特化类型>(特化类型 参数1, 特化类型 参数2 , …) 在函数名后跟<>其中写要特化的类型特化的函数的函数名,参数列表要和原基础的模板函数相同,避免不必要的错误
类的模板特化分为两种,一种是全特化,一种为偏特化
- 全特化: 即将所有的模板类型都进行特化
template <class T1, class T2>
class Test{
}
//全特化
template <> //此处同函数模板的特化一样不用写内容
class Test<int , char>{
}
- 偏特化:对于模板的类型做一些限制
- 偏特化份为两种 一种是部分特化,一种是对于模板类型的进一步限制
- 部分特化:就是只对函数模板的一部分模板类型进行特化
template <class T1, class T2>
class Test2{
}
//部分特化
template <class T1> //此处只需写未进行特化的模板类型,特化过的就不用写
class Test2<T1 , char>{
}
- 对类型的范围的限制,主要的类型基础不变
template <class T1, class T2>
class Test2{
}
//对模板类型的范围做出一定的限制
template <class T1 , class T2 > //此处只需写未进行特化的模板类型
class Test2<T1* , T2*>{
}
compare的模板函数进行数据比较:
#include <iostream>
#include <string.h>
using namespace std;
template <class T>
int compare(const T& left, const T& right)
{
if (left < right) return -1;
else if (left > right) return 1;
else return 0;
}
template<class T,int size>
int compare(T(&v1)[size], T(&v2)[size])
{
for (int i = 0; i <= size;i++)
{
if (v1[i] > v2[i]) return 1;
else if (v1[i] < v2[i]) return -1;
}
return 0;
}
template <>
int compare<const char*>(const char* const& v1, const char* const& v2)
{
return strcmp(v1, v2);
}
int main(int argc, char** argv) {
cout<< compare(3, 4)<<endl;
cout << compare(3.7,3.5)<<endl;
cout << compare("aaa","aab")<<endl;
const char* a = "abc";
const char* b = "aba";
cout << compare(a, b);
}
结果:
二、模板类
1.Queue
Queue<T> 是一种只能访问第一个和最后一个元素的容器适配器,只能在容器的末尾添加新元素,只能从头部移除元素。使用队列,要先包含头文件 : #include<queue>
queue.push(elem) //把元素压入队列尾部
queue.pop() //删除队首元素,但不返回
queue.front() //返回队首元素,但不删除
queue.back() //返回队尾元素,但不删除
queue.size() //返回队列中元素的个数
queue.empty() //检查队列是否为空,如果为空返回true,否则返回false
使用front()和pop()函数前,必须用empty()判断队列是否为空
2.Stack
Stack<T> 容器适配器中的数据是先进后出的,当想访问栈内某一元素时,必须将其顶部的元素都弹出出栈后,才能访问该元素。使用栈之前,要先包含头文件 : #include<stack>
stack.push(elem); //往栈头添加元素
stack.pop(); //从栈头移除第一个元素
stack.top(); //返回栈顶元素
stack.empty(); //判断堆栈是否为空,栈空返回true,栈非空返回false
stack.size(); //返回堆栈的大小
3.代码实现
#ifndef QUEUE_H
#define QUEUE_H
#include <iostream>
using namespace std;
//定义类模板
template<class Type> class Queue;
template<class Type> class QueueItem {
QueueItem(const Type& t) : item(t), next(0) {}
Type item;
QueueItem* next;
friend class Queue<Type>;
//输出运算符的重载
friend ostream& operator<<(ostream& os, const Queue<Type>& q);
QueueItem<Type>* operator++() {
return next;
}
Type& operator*() {
return item;
}
};
template<class Type> class Queue {
public:
Queue() : head(0), tail(0) {}
Queue(const Queue& q) : head(0), tail(0) {
copy_items(q);
}
//成员函数模板
template <class It>
Queue(It beg, It end) : head(0), tail(0) { copy_items(beg, end); }
template<class It> void assign(It beg, It end);
Queue& operator=(const Queue&);
//析构函数
~Queue() { destroy(); }
Type& front() { return head -> item; }
const Type& front() const { return head -> item; }
//元素入队
void push(const Type&);
//队尾元素出队
void pop();
bool empty() const { return head == 0; }
//输出符重载(第二个参数表示待输出的队列)
//(全局)友元函数
friend ostream& operator<<(ostream& os, const Queue<Type>& q) {
os << "< ";
QueueItem<Type>* p;
for (p = q.head; p; p = p -> next) {
os << p->item << " ";
}
os << ">";
return os;
}
const QueueItem<Type>* Head() const { return head; }
const QueueItem<Type>* End() const { return (tail == NULL) ? NULL : tail -> next; }
private:
QueueItem<Type>* head;
QueueItem<Type> *tail;
void destroy();
void copy_items(const Queue&);
template<class It>
void copy_items(It beg, It end);
};
template<class Type>
void Queue<Type>::pop() {
QueueItem<Type>* p = head;
head = head -> next;
delete p;
}
template<class Type>
void Queue<Type>::push(const Type& val) {
QueueItem<Type>* pt = new QueueItem<Type>(val);
if (empty()) {
head = tail = pt;
}
else {
tail -> next = pt;
//元素添加到队列后tail指针指向该元素
tail = pt;
}
}
template < >
void Queue<const char*>::push(const char* const& val);
template < >
void Queue<const char*>::pop();
template <class Type>
void Queue<Type>::copy_items(const Queue& orig) {
for (QueueItem<Type>* pt = orig.head; pt; pt = pt -> next) {
push(pt -> item);
}
}
template <class Type>
Queue<Type>& Queue<Type>::operator=(const Queue& q)
{
destroy();
copy_items(q);
}
template<class Type> template<class It> void Queue<Type>::assign(It beg, It end)
{
destroy();
copy_items(beg, end);
}
template<class Type> template<class It> void Queue<Type>::copy_items(It beg, It end)
{
while (beg != end) {
push(*beg);
++beg;
}
}
//销毁队列
template<class Type>
void Queue<Type>::destroy()
{
while (!empty()) {
pop();
}
}
void TestQueue();
#endif
main.cpp文件:
int main() {
Queue<int> qt;
double d = 3.3;
qt.push(1);
qt.push(d);
qt.push(10);
cout<<qt;
short a[5] = {0,3,6,9};
Queue<int> qi(a,a+5);
cout<<endl;
cout<<qi;
return 0;
}
结果为:
三、模板类AutoPtr
1.构造函数
AutoPtr(T* pData);
template<class T>
AutoPtr<T>::AutoPtr(T* pData)
{
m_pData = pData;
m_nUser = new int(1);
}
2.析构函数
~AutoPtr();
template<class T>
AutoPtr<T>::~AutoPtr()
{
decrUser();
}
template<class T>
void AutoPtr<T>::decrUser()
{
--(*m_nUser);
if((*m_nUser)==0){
delete m_pData;
m_pData = 0;
delete m_nUser;
m_nUser = 0;
}
}
3.拷贝构造函数
AutoPtr<T>::AutoPtr(const AutoPtr<T>& h);
AutoPtr<T>::AutoPtr(const AutoPtr<T>& h)
{
m_pData = h.m_pData;
m_nUser = h.m_nUser;
(*m_nUser)++;
}
4.运算符重载
AutoPtr<T>& operator=(const AutoPtr<T>& h);
AutoPtr<T>& AutoPtr<T>::operator=(const AutoPtr<T>& h)
{
if(this==&h) return *this;
decrUser();
m_pData = h.m_pData;
m_nUser = h.m_nUser;
(*m_nUser)++;
return *this;
}
T* operator‐>(){
return m_pData;
}
T& operator*(){
return *m_pData;
}
const T& operator *() const{
return *m_pData;
}
const T* operator ‐>() const{
return m_pData;
}
5.主函数调用AutoPtr
void TestAutoPtr()
{
AutoPtr<CMatrix> h1(new CMatrix);
double data[6] = {1,2,3,4,5,6};
h1->Create(2,3,data);
cout<<*h1;
AutoPtr<CMatrix> h2(h1);
(*h2).Set(0,1,10);
cout<<*h1<<*h2;
}