C++ 12:函数模板,模板函数,类模板


1. 函数模板

1.1 函数模板特点

(1)函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,简化重载函数的设计。函数模板定义如下:template<模板参数表>返回类型函数名(形式参数表) {.....; }//函数体

(2)<模板参数表>(template parameter list)尖括号中不能为空,参数可以有多个,用逗号分开。
模板参数主要是模板类型参数。

(3)模板类型参数(template type parameter)代表一种类型,由关键字class或typename(建议用typename )后加一个标识符构成,在这里两个关键字的意义相同,它们表示后面的参数名代表一个潜在的内置或用户定义的类型。

(4)函数模板根据一组实际类型或(和)值构造出独立的函数的过程通常是隐式发生的,称为模板实参推演(templateargument deduction)。

(5)为了判断用作模板实参的实际类型,编译器需检查函数调用中提供的函数实参的类型。ia 的类型为int数组,dx的类型为double 数组。都被用来决定每个实例的模板参数。该过程称为模板实参推演。

1.2 代码示例

1.2.1 例1:类型推演

代码示例

#include<iostream
#include<typeinfo>
using namespace std;
template<class T>
void fun(T a)
{
    T x, y;
    cout << "T type:" << typeid(T).name() << endl;
    cout << "a type:" << typeid(a).name() << endl;
}
int main()
{
    //int x = 10;//int     int*
    //const int x=10;//int     const int*
    /*fun(x);
    fun(&x);*/
    /*
    int x=10;
    const int y=10;
    int*xp=&x;
    const int*yp=&y;
    fun(xp);
    fun(yp);
     //int*   const int* */
}

运行结果
在这里插入图片描述

1.2.2 例2:类型推演失败

因为明确给出需要指针类型,给出的是整型,类型不匹配,推演失败,函数都可以重载

using namespace std;
template<class T>
void fun(T* a)//必须是指针所有推演失败 部分泛化
{
    T x, y;
    cout << "T type: " << typeid(T).name() << endl;
    cout << "a type: " << typeid(a).name() << endl;
}
int main()
{
    int x = 10;
    const int y = 10;
    fun(x);
    fun(y);
    //推演失败解决办法:加引用
    fun(&x);//int   int*
    fun(&y);//int   const int*
    return 0;
}

1.2.3 例3:类型推演

template<class T>
void fun(T& a)
{
    T x, y;
    cout << "T type: " << typeid(T).name() << endl;
    cout << "a type: " << typeid(a).name() << endl;
}
int main()
{
    int x = 10;
    const int y = 10;
    int* xp = &x;
    const int* yp = &y;
    fun(x);
    fun(y);
    fun(&x);
    fun(&y);
    fun(xp);
    fun(yp);

    return 0;
}

2. 模板函数

2.1 定义

在编译main()函数中,由编译函数模板(functron template)而生成的函数,称为模板函数(template function).这两个概念须分清楚。

2.2 泛化

void fun(T a)//完全泛型
void fun(T *a);//部分泛型
void fun<char>(const char* a)//完全特化

2.3 模板类型推演示例

2.3.1 类型推演示例

template<class T>
void fun(T a)
{
    T x, y;
    cout << "T type: " << typeid(T).name() << endl;
    cout << "a type: " << typeid(a).name() << endl;
}
int main()
{
    int x = 10;
    const int y = 20;
    int* xp = &x;
    const int* yp = &y;
    fun(x);//int           int
    fun(y);//int           int
    fun(&x);//int*         int*
    fun(&y);//const int*   const int*
    fun(xp);//int*         int*
    fun(yp);//const int*   const int*
    fun(&xp);//int**       int**
    fun(&yp);//const int** const int**
}

2.3.2 推演失败案例,类型不匹配

template<typename T>
void fun(T* a)
{
    T x, y;
    cout << typeid(T).name() << endl;
    cout << typeid(a).name() << endl;
}
int main()
{
    int x = 10;
    const int y = 20;
    fun(x);//推演失败(类型不匹配)
    fun(y);//推演失败
    return 0;
}

2.3.3 无类型指针示例

代码示例

template<typename T>
void fun(T* a)
{
    T x, y;
    cout << typeid(T).name() << endl;
    cout << typeid(a).name() << endl;
}
int main()
{
    int x = 10;
    const int y = 20;
    int* xp = &x;
    const int* yp = &y;
    void* p = &x;//无类型指针
    //带有类型萃取能力
    fun(&x);//int          int*
    fun(&y);//const int    const int*
    fun(p);//void          void*    
    return 0;
}

无类型无法定义变量

2.4.模板函数的引用

代码示例

template<typename T>
void fun(T& a)//引用是和变量名结合,不是和类型名结合
{
    T x = 0, y = 0;//进行初始化才能编译通过
    cout << typeid(T).name() << endl;
    cout << typeid(a).name() << endl;
}
int main()
{
    int x = 10;
    const int y = 20;
    fun(x);//int         int&
    fun(y);//const int   const int&
    return 0;
}

运行结果
在这里插入图片描述

2.5 引用与指针结合

代码示例

template<typename T>
void fun(T& a)//引用是和变量名结合,不是和类型名结合
{
    T x = 0, y = 0;//进行初始化才能编译通过
    cout << typeid(T).name() << endl;
    cout << typeid(a).name() << endl;
}
int main()
{
    int x = 10;
    const int y = 20;
    int* xp = &x;
    const int* yp = &y;
    fun(xp);//int*          int*&
    fun(yp);//const int*    const int*&

    return 0;
}

运行结果
在这里插入图片描述

2.6 引用与二级指针结合

template<typename T>
void fun(T const& a)//引用是和变量名结合,不是和类型名结合
{
    T x = 0, y = 0;//进行初始化才能编译通过
    cout << typeid(T).name() << endl;
    cout << typeid(a).name() << endl;
}
int main()
{
    int x = 10;
    const int y = 20;
    fun(&x);//int* int const*
    fun(&y);//int* int const*

    return 0;
}

在这里插入图片描述

2.7 模板函数类型推演示例

代码示例

template<class T>
void fun(T a)
{
    cout << "T a" << endl;
}

template<class T>
void fun(T* a)
{
    cout << "T *a" << endl;
}

template<class T>
void fun(const T* a)
{
    cout << "const T*" << endl;
}
int main()
{
    int x = 10;
    const int y = 20;
    fun(x);//T
    fun(&x);//T*
    fun(&y);//const T*
}

运行结果

在这里插入图片描述

2.8 模板函数的重载

template<class T>
void fun(T a, int)
{

}
template<class T>
void fun(T a, char)
{

}
int main()
{
    fun(12, 23);
    fun(12, 'a');
    return 0;
}

3. 类模板

3.1 概念

(1)类模板不存在推演过程
(2)类模板中的函数都是模板函数

代码示例

void push(const T& x)
{
	cout<<N<<endl;
	N=100;
}

3.2 代码示例

//类模板
template<class T>
class stack
{
    T* data;
    size_t count;
public:
    void Push(const T& x);
};

3.3 模板函数类型

template<class T,int N>
class Stack
{
    T data[N];
public:
    void push(const T& x);
};
int main()
{
    //is和ist类型不相同
    Stack<int, 100> is;
    Stack<int, 10> ist;

    return 0;
}

3.4 模板函数中的new

template<class T>
class Array
{
    enum { INIT = 10 };
    T* data;//.heap 10
    size_t capacity;//10
    size_t count;//5
public:
    Array()
    {
        count = 0;
        data = new T[capacity = INIT];//连续开辟数组,调动构造函数,对每个空间构造函数
    }
    ~Array() { delete[]data; }
};
int main()
{
    Array<int> ar;
    Array<double> dr;
}

3.5 模板类型识别

int main()
{
    Array<int> a;//不是模板类型,已经被实例化
    Array b;
}

3.6 综合代码示例

#define _CRT_SECURE_NO_WARNINGS
#include"stdio.h"
#include<iostream>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<vector>
#include<map>
#include<list>
#include<thread>
#include<mutex>
#include<typeinfo>
#include<map>
#include<queue>
#include<functional>
using namespace std;

class String
{
protected:
    struct StrNode
    {
        int ref;  // 引用计数
        int len;  // 字符串的长度
        int size; // 柔性数组的容量
        char data[];
    };
private:
    StrNode* pstr;
public:
    String(const char* p = NULL) :pstr(NULL)
    {
        if (p != NULL)
        {
            int sz = strlen(p);
            pstr = (StrNode*)malloc(sizeof(StrNode) + sz * 2 + 1);
            pstr->ref = 1;
            pstr->len = sz;
            pstr->size = sz * 2;
            strcpy(pstr->data, p);
        }
    }
    ~String()
    {
        if (pstr != NULL && --pstr->ref == 0)
        {
            free(pstr);
        }
        pstr = NULL;
    }
    String(const String& str) :pstr(NULL)
    {
        if (str.pstr != NULL)
        {
            pstr = str.pstr;
            pstr->ref += 1;
        }
    }
    String& operator=(const String& s)
    {
        if (this == &s) return *this;
        if (this->pstr != NULL && --this->pstr->ref == 0)
        {
            free(this->pstr);
        }
        this->pstr = s.pstr;
        if (this->pstr != NULL)
        {
            this->pstr->ref += 1;
        }
        return *this;
    }

    char& operator[](const int index)
    {
        //写时拷贝
        if (pstr == NULL) exit(1);
        assert(index >= 0 && index <= pstr->len - 1);
        //越界问题
        if (pstr->ref > 1)
        {
            int total = sizeof(StrNode) + pstr->size + 1;
            StrNode* newnode = (StrNode*)malloc(total);
            memmove(newnode, pstr, total);
            newnode->ref = 1;
            pstr->ref -= 1;
            pstr = newnode;
        }
        return pstr->data[index];
    }
    const char& operator[](const int index) const
    {
        return (*this)[index];
    }
    ostream& operator<<(ostream& out) const
    {
        if (pstr != NULL)
        {
            out << pstr->data;
        }
        return out;
    }
    String(String&& s);//移动构造
    String& operator=(String&& s);//移动赋值
};
ostream& operator<<(ostream& out, const String& s)
{
    s << out;
    return out;
}
int main()
{
    String s1("yhping");
    String s2(s1);

    String s3("hello");
    String s4("new");

    //s1 = s1 + s4;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值