天天看点

CPP_template

泛型编程是独立于任何特定类型的方式编写代码。模板是泛型编程的基础,模板使程序员能够快速建立具有类型安全的类库集合和函数集合,它的实现,方便了大规模的软件开发。

模板提供通用类型和通用函数,定义中包含template,和一对尖括号<>,尖括号里面是模板参数。模板参数与普通参数的区别在于,模板参数不仅可以传变量和值,还可以传类型。模板参数中定义类型可以使用关键字typename或class(效果一样,有的开发者为区分,函数使用typename,类使用class,实际等同);参数名默认是T,可以为任意字符,效果等同,只是T较常用,默认。

模板应放到头文件中。模板本质上就是一种宏定义。

一. 函数模板

template<typename T> 
返回类型 function(形式参数表)
{
    //函数定义体
}      

template ---- 声明创建模板

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

T ---- 通用数据类型,名称可以替换,通常为大写字母

template <class T>
void myswap(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}      

使用函数模板有两种方式:自动类型推导、显示指定类型

void test01()
{
    int a = 10, b = 20;
//    myswap(a, b);
    myswap<int>(a, b);
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;      

模板的目的是为了提高复用性,将类型参数化。

注:1)自动类型推导,必须推导出一致的数据类型T才可以使用。

2)模板必须要确定出T的数据类型,才可以使用。(比如函数没有参数且不能自动推导出T类型)

template<class T>
void func()
{
    cout <<  "call func" << endl;
}

int main()
{
//    func();  // 不能推导出T类型
    func<int>();
    return 0;
}      

普通函数和函数模板区别:

普通函数调用可以发生自动类型转换(隐式类型装换);函数模板调用时如果利用自动类型推导,不会发生隐式类型转换;如果利用显示指定类型的方式,可以发生隐式类型转换。

建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T。

普通函数与函数模板的调用规则(函数重载时):

1)如果函数模板和普通函数都可以实现,优先调用普通函数;

2)可以通过空模板参数列表来强制调用函数模板;myPrintf<>(a, b);

3)函数模板也可以发生重载;

4)如果函数模板可以产生更好的匹配,优先调用函数模板。

建议在使用模板时,不要提供普通函数(两者不要同时出现)。

模板局限性:自定义类型操作

C++为了解决自定义数据类型的无法正常运行问题,提供模板的重载,为这些特定的类型提供具体化的模板。

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <string>

using namespace std;

class Person
{
public:
    Person(string name, int age){
        this->m_name = name;
        this->m_age = age;
    }

    string m_name;
    int m_age;
};

template <class T>
bool myCompare(T &a, T&b)
{
    if(a == b){
        return true;
    } else {
        return false;
    }
}

// 利用具体Person的版本实现代码,具体化优先调用
template<> bool myCompare(Person &p1, Person &p2)
{
    if(p1.m_name == p2.m_name && p1.m_age == p2.m_age){
        return true;
    } else {
        return false;
    }
}

void test02()
{
    Person p1("Tom", 10);
    Person p2("Tom", 10);
    cout << myCompare(p1, p2) << endl;
}

int main(int argc, char *argv[])
{
    test02();

    pause();
    return 0;
}      

利用具体化的模板可以解决自定义类型的通用化。

学习模板并不是为了能写模板,而是在STL能够运用系统提供的模板。

二. 类模板

template <模板参数表> class 类名{};

template<class T1, class T2>
class 类{
    类成员声明;
};      

T是占位符类型名称,可以在类被实例化的时候进行指定。您可以使用一个逗号分隔的列表来定义多个泛型数据类型。

在类模板以外定义成员函数

template <模板参数表> 类型名 类名<参数列表>::函数名(参数表)

模板类中的函数都是模板函数。

template <class T> Node<T>::~Node()

{

......

}

参考:

继续阅读