C++实验三 模板

实验环境

操作系统:win10
gcc:8.1.0
开发软件:qt5.14.2

模板概念

在C++的相关代码开发中,我们常常会遇到的是关于代码通用性的问题;模板就是C++支持参数化程序设计的工具,通过它可以实现参数化多态性。这里可以看一下两个例子。

int sum(int x,int y)
{
	return x+y;
}
double sum(double x,double y)
{
	return x+y;
}

事实上两个函数除了数据类型以外进行的功能是一样的,但如果像这样分开写其实大大的降低了代码整体的通用性,对于设计和使用都是不方便的选择。这就是模板需要起作用的地方,模板的定义如下

template<模板参数表>
类型名 函数名(参数表)
{
	函数
}

为了方便理解,以上述的例子为出发点进行衍生。

#include<iostream>
using namespace std;
template<typename test>
test sum(test a,test b)
{
	return a+b;
}
int main()
{
	int test1=1,test2=2;
	double test3=3,test4=4;
	cout<<sum(test1,test2)<<endl;
	cout<<sum(test3,test4)<<endl;
	return 0;
}

在这里插入图片描述
可以看到,这样的方式成功完成了对一般模板函数的成功运用。

特化模板函数

但此时需要考虑一个特殊状况,使用模板时会遇到一些特殊的类型需要特殊处理,不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板函数,如下所示。

template<class test>
bool Isequal(test &t1, test &t2)
{
	return t1 == t2;
}

上述的函数可以判断传入的两个参数是否相等,但显而易见的,当数据类型为字符型时,上述函数无法生效,故在此使用特化的模板函数。

template<>
bool Isequal<char*>(char*& t1, char*& t2)
{
	return strcmp(t1, t2) == 0;
}

上面展示的就是特化的模板函数,需要注意几点

  • 使用模板特化时,必须要先有基础的模板函数(就是上面第一个模板函数)
  • template 后直接跟<> 里面不用写类型
  • 函数名<特化类型>(特化类型 参数1, 特化类型 参数2 , …) 在函数名后跟<>其中写要特化的类型
  • 特化的函数的函数名,参数列表要和原基础的模板函数相同
    同样 我们简单的运行来验证结果。
    在这里插入图片描述
    从上图可以看到,运行的结果符合预期,特化的函数成功运作了。

模板类

既然存在模板函数的概念,同样也存在模板类的概念。使用类模板的过程可以使得程序员为类定义一种模式,使得类中的部分数据成员,部分成员函数的参数,返回值和局部变量能取不同的类型。这里为了方便说明,简单的建立一个**队列(queue)**的类来进行实践。

首先让我们对简单的模板类进行说明。

template <typename T>
class Complex{
    
public:
    //构造函数
    Complex(T a, T b)
    {
        this->a = a;
        this->b = b;
    }
    
    //运算符重载
    Complex<T> operator+(Complex &c)
    {
        Complex<T> tmp(this->a+c.a, this->b+c.b);
        return tmp;
    }
        
private:
    T a;
    T b;
}

int main()
{
    //对象的定义,必须声明模板类型,因为要分配内容
    Complex<int> a(10,20);  
    Complex<int> b(20,30);
    Complex<int> c = a + b;
    
    return 0;
}

其中简单的展示了类模板的使用方式,重要的部分都有进行注释。

队列类

话不多说,先把实现的代码放在下面

#include <iostream>
using namespace  std;
template<class T>
struct Node {
    T data;
    Node *next;
};

template<class T>
class MyQueue {
public:
    MyQueue(); // 构造函数
    ~MyQueue(); // 析构函数
    void Push(const T& x); // 压入队列
    T Front(); // 获取队头元素
    T Back(); // 获取队尾元素
    void Pop(); // 删除队头元素
    bool Empty() const; // 判断队列是否为空
    int Size() const; // 返回队列的大小
private:
    Node<T> *head; // 头指针
    Node<T> *tail; // 尾指针
};

// 构造函数
template<class T>
MyQueue<T>::MyQueue() {
    head = tail = NULL;
}

// 析构函数
template<class T>
MyQueue<T>::~MyQueue() {
    Node<T> *current;

    while(head != NULL) {
        current = head;
        head = head->next;
        delete current;
        current = NULL;
    }
}

// 压入队列
template<class T>
void MyQueue<T>::Push(const T &x) {
    Node<T> *current;

    current = new Node<T>();
    if(current == NULL) {
        std::cerr << "申请空间失败!\n";
        exit(1);
    }
    current->data = x;
    current->next = NULL;
    if(head == NULL)
        head = current;
    else
        tail->next = current;
    tail = current;
}

// 获取队头元素
template<class T>
T MyQueue<T>::Front() {
    Node<T> *current;
    if(head == NULL) {
        std::cout << "队列为空!\n";
        exit(1);
    }
    current = head;
    return current->data;
}

// 获取队尾元素
template<class T>
T MyQueue<T>::Back() {
    Node<T> *current;
    if(head == NULL) {
        std::cout << "队列为空!\n";
        exit(1);
    }
    current = tail;
    return tail->data;
}

// 删除队头元素
template<class T>
void MyQueue<T>::Pop() {
    if(head == NULL) {
        std::cout << "队列为空!\n";
        exit(1);
    }
    head = head->next;
}

// 判断队列是否为空
template<class T>
bool MyQueue<T>::Empty() const {
    if(head == NULL)
        return true;
    return false;
}

// 返回队列的大小
template<class T>
int MyQueue<T>::Size() const {
    int n;
    Node<T> *current;

    n = 0;
    current = head;
    while(current != NULL) {
        n++;
        current = current->next;
    }
    return n;
}

可以看到,上面的类在使用了模板类的前提下实现了队列的简单的构造函数,析构函数,向队列中加入元素,删除队列元素,返回队列长度,获取队头和队尾的长度等的基本操作。
先让我们看一下实现的效果
在这里插入图片描述

与模板类的实现在上述的队列代码中都有体现,以下任然需要补充一些在使用类模板时会遇到的问题。

  • 模板类本身未指定所使用的数据类型,不能单独编译模板类的实现。 只用在使用模板类的阶段,指定了模板中的数据类型,编译器才能正常编译。因此,在实际开发中,必须把实现全部写在头文件里面,把声明和实现分开的做法不可取。
  • 模版不支持在局部函数中声明定义或使用
  • 自动类型推导,必须推导出一致的数据类型T,才可以使用模板必须要确定出T的数据类型,才可以使用。
  • 模版类的定义和实现不能分开写在不同文件中,否则会导致编译错误
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值