【C++】模板机制

C++中提供两种模板机制:函数模板和类模板

函数模板

建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表;

template<typename T>

函数声明或定义

//函数模板
template<typename T> //声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用数据类型;
void MySwap(T& a, T& b)
{
        T temp = a;
        a = b;
        b = temp;
}

void test02()
{
        //利用函数模板来交换
        //两种方式使用函数模板
        //1、自动类型推导
        int a = 1, b = 2;
        MySwap(a, b);
        cout << a << " " << b << endl;

        //2、显示指定类型
        double c = 1.1, d = 2.2;
        MySwap<double>(c, d);
        cout << c << " " << d << endl;
}

注意事项:

  • 自动类型推导,必须推导出一致的数据类型T,才可以使用

  • 模板必须要确定出T的数据类型,才可以使用

普通函数和函数模板

区别
  • 普通函数调用时可以发送自动类型转换(隐式类型转换)

  • 函数模板调用时,如果利用自动类型推导,不会发送隐式类型转换

  • 如果利用显示指定类型的方式,可以发送隐式类型转换

    //普通函数
    int add01(int a, int b)
    {
    return a + b;
    }

    template<class T>
    T add02(T a, T b)
    {
    return a + b;
    }

    void test03()
    {
    int a = 10;
    int b = 20;
    char c = 'a';//a -->97
    cout << add01(a, b) << endl;
    cout << add01(a, c) << endl;

          //1、自动类型推导
          cout << add02(a, b) << endl;
          //cout << add02(a, c) << endl;//报错
          //2、显示指定类型
          cout << add02<int>(a, c) << endl;
    

    }

规则
  • 如果函数模板和普通函数都可以实现,优先调用普通函数

  • 可以通过空模板参数列表来强制调用函数模板

  • 函数模板也可以发生重载

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

add02<>(a,b):强制调用
template<class T>

void Print(T a, T b)

{

cout<<"调用模板"<<endl;

}

template<class T>

void Print(T a, T b,T c)

{

cout<<"重载模板"<<endl;

}

局限性

模板不是万能的,有些特定数据类型,需要用具体化方式做特殊实现

class Person
{
public:
        Person(string name,int age)
        {
                _name = name;
                _age = age;
        }
public:
        string _name;
        int _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._name == p2._name && p1._age == p2._age)
        {
                return true;
        }
        return false;
}

void test04()
{
        int a = 10;
        int b = 20;
        bool ret = myCompare(a, b);
        cout << ret << endl;

        Person p1("Tom", 10);
        Person p2("Tom", 10);
        ret = myCompare(p1, p2);
        cout << ret << endl;
}

类模板

//类模板
template<class NameType,class AgeType>
class Person
{
public:
        Person(NameType name, AgeType age)
        {
                _name = name;
                _age = age;
        }
public:
        NameType _name;
        AgeType _age;
};

void test01()
{
        Person<string, int> p1("Tom", 9);
}
类模板和函数模板区别
  • 类模板没有自动类型推导的使用方式

//Person p1("Tom", 9); 错误,无法使用自动类型推导

Person<string, int> p1("Tom", 9); //正确,只能用显示指定类型

  • 类模板在模板参数列表中可以有默认参数

template<class NameType,class AgeType = int>

Person<string> p1("Tom", 9);

类模板中成员函数创建时机

  • 普通类中的成员函数一开始就可以创建

  • 类模板中的成员函数在调用时才创建

类模板对象做函数参数

三种传入方式:

  • 指定传入类型 --直接显示对象的数据类型

  • 参数模板化 --将对象中的参数变为模板进行传递

  • 整个类模板化 --将这个对象类型模板化进行传递

    //类模板对象做函数参数
    template<class T1,class T2>
    class Person
    {
    public:
    Person(T1 name, T2 age)
    {
    _name = name;
    _age = age;
    }
    void show()
    {
    cout << "姓名:" << _name << ", 年龄:" << _age << endl;
    }
    public:
    T1 _name;
    T2 _age;
    };
    //1、指定传入类型
    void printPerson1(Person<string, int> &p)
    {
    p.show();
    }
    void test02()
    {
    Person<string, int> p1("Tom", 20);
    printPerson1(p1);
    }
    //2、参数模板化
    template<class T1, class T2>
    void printPerson2(Person<T1, T2>& p)
    {
    p.show();
    cout <<"T1的类型为:" << typeid(T1).name() << endl;
    cout <<"T1的类型为:" << typeid(T2).name() << endl;
    }
    void test03()
    {
    Person<string, int> p1("Tom", 20);
    printPerson2(p1);
    }
    //3、整个类模板化
    template<class T>
    void printPerson3( T &p)
    {
    p.show();
    cout << "T的数据类型为:" << typeid(T).name() << endl;
    }
    void test04()
    {
    Person<string, int> p1("Tom", 20);
    printPerson3(p1);
    }

类模板与继承

//类模板与继承
template<class T>
class Base
{
        T m;
};

class Son :public Base<int>//必须要知道父类中的T类型,才能继承给子类
{

};

//如果想灵活指定父类中的T类型,子类也需要变成类模板
template<class T1,class T2>
class Son2 :public Base<T1>
{
        T2 obj;
};

void test05()
{
        Son2<int, char> s2;
}

类模板成员函数的类外实现

//类模板成员函数的类外实现
template<class T1, class T2>
class Person
{
public:
        Person(T1 name, T2 age);
        void show();
public:
        T1 _name;
        T2 _age;
};
template<class T1,class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
        this->_name = name;
        this->_age = age;
}

template<class T1, class T2>
void Person<T1, T2>::show()
{
        cout << "姓名:" << _name << ", 年龄:" << _age << endl;
}

void test05()
{
        Person<string, int> p("Tom", 20);
        p.show();
}

类模板的分文件编写

就是声明在.h文件,实现在.cpp中实现:

报错原因:

类模板中成员函数创建时间是在调用的时候才会创建;所以链接.h文件的时候,并不会生成成员函数,所以在调用的时候就会报错,找不到这个成员函数

解决方法:

  • 直接包含.cpp源文件

  • 将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制的

类模板与友元

全局函数类内实现-直接在类内声明友元即可

全局函数类外实现-需要提前让编译器知道全局函数的存在

//提前让编译器知道Person类的存在
template<class T1, class T2>
class Person;
//类外实现
template<class T1, class T2>
void show2(Person<T1, T2>p)
{
        cout << "姓名:" << p._name << ", 年龄:" << p._age << endl;
}


template<class T1,class T2>
class Person
{
        //全局函数,类内实现
        friend void show1(Person<T1,T2>p)
        {
                cout << "姓名:" << p._name << ", 年龄:" << p._age << endl;
        }
        //全局函数,类外实现
        //加空模板参数列表
        friend void show2<>(Person<T1, T2>p);
public:
        Person(T1 name, T2 age)
        {
                _name = name;
                _age = age;
        }
        
public:
        T1 _name;
        T2 _age;
};

void test06()
{
        Person<string, int>p("Tom", 20);
        show1(p);

        Person<string, int>p1("Jorry", 20);
        show2(p1);
}
相关推荐
Tech Synapse1 分钟前
Java 动态设置 JVM 参数的方法
java·开发语言·jvm
ALISHENGYA7 分钟前
Python基础经典编程练习题,含答案
python·算法
吃着火锅x唱着歌13 分钟前
PHP7内核剖析 学习笔记 第三章 数据类型
android·笔记·学习
keira67414 分钟前
【21天学习AI底层概念】day5 机器学习的三大类型不能解决哪些问题?
人工智能·学习·机器学习
martian66521 分钟前
深入详解人工智能机器学习常见算法中的K-means聚类
人工智能·算法·机器学习·k-means聚类
宽广26 分钟前
java aspose word 模板根据数据导出pdf
java·开发语言·pdf·c#·word
、南城不南 ╯42 分钟前
最小二乘法拟合出二阶响应面近似模型
算法·最小二乘法
数据小爬虫@1 小时前
利用Python爬虫技术获取商品销量详情
开发语言·爬虫·python
字节高级特工1 小时前
C++---入门
开发语言·c++·算法