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()
{
......
}

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

using namespace std;

template<class NameType=string, class AgeType=short>
class Person {
    public:
    Person(NameType name, AgeType age) {
      m_name = name;
      m_age = age;
    }

    void showInfo() {
      cout << m_name << " is " << m_age << (m_age == 1 ? " year" : " years") << " old. " << endl;
    }

    NameType m_name;
    AgeType m_age;
};

class Wang: public Person<string, short> {
};

void printPerson1(Person<string, short> &p)
{
    p.showInfo();
}

template <class NameType, class AgeType>
void printPerson2(Person<NameType, AgeType> &p){
    p.showInfo();
    cout << "\t NameType:" << typeid(NameType).name() << endl
    << "\t AgetType:" << typeid(AgeType).name() << endl;
}

template <typename T>
void printPerson3(T &p){
    p.showInfo();
    cout << "\t T:" << typeid(T).name() << endl;
}

void test1(){
    Person<string, short> p1("tony", 100);
    printPerson1(p1);

    Person<string, short> p2("AAA", 99);
    printPerson2(p2);

    Person<string, short> p3("BBB", 98);
    printPerson3(p3);

    Wang w1;
    cout << "w.m_name is " << typeid(w1.m_name).name() << endl;
    cout << "w.m_age is " << typeid(w1.m_age).name() << endl;
}

int main(){
    test1();

    pause();
    return 0;
}

 

 

参考:

1. C++模板 runoob

2. C++进阶-STL容器,你看我就够了

3. 黑马程序员 C++ https://www.bilibili.com/video/BV1et411b73Z?p=169&spm_id_from=pageDriver

posted @ 2018-09-09 15:33  yuxi_o  阅读(706)  评论(0编辑  收藏  举报