栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++实验三之模板

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++实验三之模板

文章目录
    • 一、模板函数
      • 1.1 一般模板函数
      • 1.2 特化模板函数
    • 二、模板类Queue或Stack
      • 2.1 成员模板函数
      • 2.2 模板特化
    • 三、模板类AutoPtr

一、模板函数 1.1 一般模板函数

在此之前,先说明一下模板的概念:模板就是建立通用的模具,大大提高复用性。需要注意的是:模板不可以直接使用,它只是一个框架。
而对函数模板来说,它的作用是建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。具体语法如下:

template
函数声明或定义

template — 声明创建模板

typename — 表面其后面的符号是一种数据类型,可以用class代替

T — 通用的数据类型,名称可以替换,通常为大写字母
现在用一个案例来进行演示。

#include
#include

using namespace std;

template
void mySwap(T& a, T& b) {
	T temp = a;
	a = b;
	b = temp;
}

void test01() {
	int a = 10;
	int b = 20;
	mySwap(a, b);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}
int main() {
	test01();

	return 0;
}

可以看到,交换成功

对于不同的数据类型,也可以进行交换:

另外,使用函数模板时,如果用自动类型推导,不会发生自动类型转换,即隐式类型转换。
如创建加法函数

template
T myAdd(T a, T b) {
	return a + b;
}

报错的原因是使用自动类型推导时,不会发生隐式类型转换

而加上int,用显示指定类型,可以发生隐式类型转换

1.2 特化模板函数

先创建一个比较函数

template
bool myCompare(T a, T b) {
	if (a != b)
		return false;
	else return true;
}


运行不报错。
但是,能比较类中的成员函数吗?

class Person {
public:
	string m_Name;
	Person(string name) {
	this -> m_Name = name;
	}
};


生成失败,显然是不能这样使用的。
这时候,我们就引入特化模板函数概念。
模板特化:就是在实例化模板时,对特定类型的实参进行特殊处理,即实例化一个特殊的实例版本,当以特化定义时的形参使用模板时,将调用特化版本。简而言之,就是指定了模板的使用数据类型。
另外,它的优先级高于函数模板。

template<> bool myCompare(Person a,Person b) {
	if (a.m_Name == b.m_Name) {
		return true;
	}
	else return false;
}



注意:特化模板类型必须与原模板函数一样。如果原来的一般模板函数类型,如:

template
void mySwap(T& a, T& b)

那么在特化时,原来里面带&,特化函数也必须带,否则报错。

二、模板类Queue或Stack

下面以实现Queue为案例

2.1 成员模板函数

成员模板函数,就是类模板实例化出的对象,向函数传参。
一共有三种传入方式:

  1. 指定传入的类型 — 直接显示对象的数据类型
  2. 参数模板化 — 将对象中的参数变为模板进行传递
  3. 整个类模板化 — 将这个对象类型 模板化进行传递
    在类QueueItem中,首先声明一个模板template class Type ,在这里是将整个类都模板化,其他函数都是为了这个类型的参数做工作。这很好理解:在我们创建队列Queue的时候,就是对一个数据类型进行入队出队,显而易见,里面的操作函数都是在为这一个数据类型做服务的。
    实际上,模板的本质区别就是改变替换参数类型,实现过程也很简单。我的理解是:将固定的变量类型,如int, double…用模板里的全部代替。在调用的时候再把要用的参数名传进。
    以其中一个QueueItem例为例
template class Queue;
template 
class QueueItem {
    QueueItem(const Type& t) :item(t), next(0) {}
    Type item;
    QueueItem* next;
    friend class Queue;
    friend ostream& operator<<(ostream& os, const Queue& q);
public:
    QueueItem* operator++() {
        return next;
    }
    Type& operator*() {
        return item;
    }
};
2.2 模板特化

以Queue类为例。
首先介绍模板特化的几种类型:模板函数特化、模板成员函数特化、模板类特化。
在做特化时,同创建一般函数模板一样,都需要在类前做一个模板声明并指定名称,如:template,不过括号的里面为空,即:templete<>
,随后在使用过程中,与模板函数一样,将之前写过的Type 参数名改成你想要的,如int,double…就好。

template class Queue {
public:
    Queue() :head(0), tail(0) {}
    Queue(const Queue& q) :head(0), tail(0) {
        copy_items(q);
    }
    template
    Queue(It beg, It end) : head(0), tail(0) { copy_items(beg, end); }
    template 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& q) {
        os << "< ";
        QueueItem* p;
        for (p = q.head; p; p = p‐ > next) {
            os << p‐ > item << " ";
        }
        os << ">";
        return os;
    }
    const QueueItem* Head() const { return head; }
    const QueueItem* End() const { return (tail == NULL) ? NULL : tail‐ > next; }
private:
    QueueItem* head;
    QueueItem* tail;
    void destroy();
    void copy_items(const Queue&);
    template void copy_items(It beg, It end);
};

在做特化时,将实现对应的位置改成想要使用的。

template <>
 void Queue::Push( const char * const & str)
{
    char * pVal = new char[strlen(str)+1];
     strcpy(pVal,str);
     QueItem * p = new QueItem(pVal);
    if(isEmpty())
   {
       head = tail = p;
    }
    else {
        tail‐>next = p;
       tail = p;
    }
 }
 template<>
 void Queue::Pop()
 {
     if(isEmpty())
     {
        return;
     }
     QueItem * p = head;
     head = head‐>next;
     delete []p‐>item;
     delete p;
 }
 template <> int compare(const char* const a, const char* const b)
 {
     return  strcmp(a,b);
 }
三、模板类AutoPtr

在学会了模板的几种使用方法后,下面将进行实战。
首先说一下什么是AutoPtr。智能指针是一个类,这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针。智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放,于是我们用个简单的案例来实现以下。

 #include 
#include 

using namespace std;

template 
class Shared_ptr
{
private:
    size_t* m_count;
    T* m_ptr;

public:
    //构造函数
    Shared_ptr() : m_ptr(nullptr), m_count(new size_t)
    {}

    Shared_ptr(T* ptr) : m_ptr(ptr), m_count(new size_t)
    {
        cout << "空间申请:" << ptr << endl;
        *m_count = 1;
    }

    //析构函数
    ~Shared_ptr()
    {
        --(*m_count);
        if (*m_count == 0)
        {
            cout << "空间释放:" << m_ptr << endl;
            delete m_ptr;
            delete m_count;
            m_ptr = nullptr;
            m_count = nullptr;
        }
    }

    //拷贝构造函数
    Shared_ptr(const Shared_ptr& ptr)
    {
        m_count = ptr.m_count;
        m_ptr = ptr.m_ptr;
        ++(*m_count);
    }

    //拷贝赋值运算符
    void operator=(const Shared_ptr& ptr)
    {
        Shared_ptr(std::move(ptr));
    }

    //移动构造函数
    Shared_ptr(Shared_ptr&& ptr) : m_ptr(ptr.m_ptr), m_count(ptr.m_count)
    {
        ++(*m_count);
    }

    //移动赋值运算符
    void operator=(Shared_ptr&& ptr)
    {
        Shared_ptr(std::move(ptr));
    }

    //解引用运算符
    T& operator*()
    {
        return *m_ptr;
    }

    //箭头运算符
    T* operator->()
    {
        return m_ptr;
    }

    //重载布尔值操作
    operator bool()
    {
        return m_ptr == nullptr;
    }

    T* get()
    {
        return m_ptr;
    }

    size_t use_count()
    {
        return *m_count;
    }

    bool unique()
    {
        return *m_count == 1;
    }

    void swap(Shared_ptr& ptr)
    {
        std::swap(*this, ptr);
    }

};




int main()
{
    Shared_ptr p1(new int);
    *p1 = 222;
    cout << "值:" << *p1 << " 引用计数:" << p1.use_count() << endl;
    {
        Shared_ptr p2(p1);
        *p2 = 333;
        cout << "值:" << *p2 << " 引用计数:" << p1.use_count() << endl;

        Shared_ptr p3(p2);
        *p3 = 444;
        cout << "值:" << *p3 << " 引用计数:" << p1.use_count() << endl;
    }

    cout << "引用计数:" << p1.use_count() << endl;

    Shared_ptr q1(new string("我是string1"));
    cout << (*(q1)).c_str() << endl;

    Shared_ptr q2(new string("我是string2"));
    q2.swap(q1);
    cout << (*(q1)).c_str() << endl;

    return 0;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/529493.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号