C++ 实验三 模板

目录

一、模板函数

1.一般模板函数

2.特化模板函数

二、模板类

1.Queue

2.Stack

3.代码实现

三、模板类AutoPtr

1.构造函数

2.析构函数

3.拷贝构造函数

4.运算符重载

5.主函数调用AutoPtr


一、模板函数

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值