IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++实验三 -> 正文阅读

[C++知识库]C++实验三

一、模板函数

定义:函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能。

1、一般模板函数

面向对象的继承和多态机制有效提高了程序的可重用性和可扩充性。在程序的可重用性方面,程序员还希望得到更多支持。举一个最简单的例子,为了交换两个整型变量的值,需要写下面的 Swap 函数:

void Swap(int & x, int & y)
{
    int tmp = x;
    x = y;
    y = tmp;
}

为了比较两个 double 型变量的值,还需要编写下面的 Swap 函数:

void Swap (double & xr double & y)
{
    double tmp = x;
    x = y;
    y = tmp;
}

如果还要比较两个 char 型变量的值……都需要再编写 compare函数。而这些 compare函数除了处理的数据类型不同外,形式上都是一样的。能否只写一遍 compare函数,就能用来比较各种类型的变量的值呢?继承和多态显然无法解决这个问题。因此,“模板”的概念就应运而生了。

即只需编写一次函数模板,然后基于调用函数时提供的参数类型,C++编译器将自动产生相应的函数来处理该类型的数据。如以下代码实现比较 int、double类型的变量的值。
?

#include <iostream>
using namespace std;

template<class Type>
int compare(const Type& v1, const Type& v2) 
{
    if (v1 < v2)    return -1;
    if (v1 > v2)    return 1;
    return 0;
}
int main() {
    
    int i1 = 1, i2 = 2;
    double d1 = 2.2, d2 = 1.1;
    cout << compare(i1, i2) << endl;
    cout << compare(d1, d2) << endl;
    return 0;
}

?2.特化模板函数

定义:函数模板特化是在一个统一的函数模板不能在所有类型实例下正常工作时,需要定义类型参数在实例化为特定类型时函数模板的特定实现版本。目前的标准中,模板函数只能全特化,没有偏特化

#include <iostream>
#include <cstring>
using namespace std;

template<class Type>
int compare(const Type v1, const Type v2) 
{
    if (v1 < v2)    return -1;
    if (v1 > v2)    return 1;
    return 0;
}

template < >	//函数模板特化
int compare<const char*>(const char* v1, const char* v2)
{
    return strcmp(v1, v2);
}

int main() { 
    const char* a = "hi", * b = "world";
    cout << compare(a, b) << endl;
    return 0;
}

?函数模版的特化,当函数调用发现有特化后的匹配函数时,会优先调用特化的函数,而不再通过函数模版来进行实例化。

二、模板类Queue或Stack

定义:类模板的使用能使用户为类定义一种模式,使得类中的某些数据出成员、某些成员函数的参数、返回值或局部变量能取不同类型(包括系统预定义的和用户自定义的)

1、模板类(Queue,Stack)

格式:

template<模板参数表>
class 类名
{
?? ?类成员声明
};
类模板:

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);
public:
	QueueItem<Type>* operator++()
	{
		return next;
	}
	Type & operator*()
	{
		return item;
	}
};

模板参数表中参数可以声明为该模板类的友元类,如以上代码中的第6,7行的友元类,可通过typede或者using对实例化的累模板定义别名。

2、成员模板函数

在类模板中直接声明后实例化,如果需要在类模板意外定义其成员函数,则要采用 下面的形式(现在类模板中声明成员函数):

template<模板参数表>
类型名 类名<模板参数标识符列表>::函数名(参数表){}
?

template<class Type> c1ass 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);
};
template<class Type> template<class It> 
void Queue<Type>::assign(It beg,It end)
{
	destroy();
	copy_items(beg,end);
}

3、模板特化

(1)模板函数特化:见内容一。

(2)模板成员函数特化:现为模板类Queue的成员函数push()和pop()方法实现特化,使其能够实现字符串的入队和出队操作。

template < >
void Queue<const char*>::push(const char* const& val)
{
    char* new_item = new char[strlen(val) + 1];
    strncpy(new_item, val, strlen(val) + 1);
    QueueItem < const char*> * pt = new QueueItem < const char*>(new_item);
    if (empty())
    {
        head = tail = pt;
    }
    else
    {
        tail->next = pt;
        tail = pt;
    }
}

template < >
void Queue<const char*>::pop()
{
    QueueItem<const char*>* p = head;
    delete head->item;
    head = head->next;
    delete p;
}

(3)模板类特化
?

类模板的特化:与函数模板类似,当类模板内需要对某些类型进行特别处理时,使用类模板的特化。

模板参数的类模板特化的几种类型:

  • 一是特化为绝对类型
  • 二是特化为引用,指针类型
  • 三是特化为另外一个类模板
template<>
class Queue<const char*>{//对字符类特化队列
public:
    void Push(const char* str){real_queue.Push(str);}
    void Pop(){real_queue.Pop();}
    bool isEmpty()  {return real_queue.isEmpty();}
    string front() const {return real_queue.front();}
    friend ostream & operator<<(ostream& os, Queue<const char*> &que){
        os<<que.real_queue;
    }
    const string &front() const{return real_queue.front();}
 
private:
    Queue<string> real_queue;
 
};

4.模板成员函数特化

template <>
void Queue<const char*>::Push( const char * const & str)//对字符类特化队列推进
{
    char * pVal = new char[strlen(str)+1];
    strcpy(pVal,str);
    QueItem<const char*> * p = new QueItem<const char*>(pVal);
    if(isEmpty())
    {
        head = tail = p;
    }
    else {
        tail‐>next = p;
        tail = p;
    }
}
template<>
void Queue<const char* >::Pop()//对字符类特化队列清除
{
    if(isEmpty())
    {
        return;
    }
    QueItem<const char*> * p = head;
    head = head‐>next;
    delete []p‐>item;
    delete p;
}

三、模板类AutoPtr

1.构造函数

//构造函数
AutoPtr(T* pData);

template < class T>
AutoPtr<T>::AutoPtr(T* pData)
{
    m_pData = pData;
    //初始化用户数为1
    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(const AutoPtr<T>& h);

template < class T>
AutoPtr<T>::AutoPtr(const AutoPtr<T>& h) 
{
    m_pData = h.m_pData;
    m_nUser = h.m_nUser;
    //用户数加1
    (*m_nUser)++;
}

4.等号、->、*等运算符重载

//等号的重载
AutoPtr<T>& operator=(const AutoPtr<T>& h);

template < class T>
AutoPtr<T>& AutoPtr<T>::operator=(const AutoPtr<T>& h)
{
    decrUser();
    m_pData = h.m_pData;
    m_nUser = h.m_nUser;
    (*m_nUser)++;
}

//指针运算符重载(返回的指针允许被改变)
T* operator ->() 
{
	return m_pData;
}
//指针运算符重载(返回的指针不允许被改变)
const T* operator -> () const 
{
	return m_pData;
}
//返回一个对象(能使用成员运算符(".")来访问成员变量)
T& operator*() 
{
	return *m_pData;
}
const T& operator *() const 
{
	return *m_pData;
}

5.主函数调用AutoPtr

#include<iostream>
#include "queue.h"
#include "autoptr.h"
#include "CMatrix.h"
using namespace std;

int main() {
    //创建一个CMatrix类的指针并交给智能指针类进行管理
    AutoPtr<CMatrix> h1(new CMatrix);
    double data[6] = { 1,2,3,4,5,6 };
    //生成一个2行3列的数组
    h1->Create(2, 3, data);
    cout << *h1 << endl;
    //h2(拷贝构造函数的使用)和h1指向的是同一个地方
    AutoPtr<CMatrix> h2(h1);
    (*h2).Set(0, 1, 10);
    cout << *h1 << *h2 << endl;

    return 0;
}

总结:

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

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-23 12:09:25  更:2021-11-23 12:11:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:25:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码