泛型编程

主要技术:模板
分类:函数模板和类模板

函数模板

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

    template<typename T>
    函数声明或定义

template:声明创建模板
typename:表面后面的符号是一种函数类型,可以用class代替
T:通用的数据类型,名称可以替换,通常为大写

    template<typename T>//声明一个模板,告诉编译器后面代码紧跟着的T不要报错,T是一个通用数据类型
    //template<class T>也可
    void myswap(T &a,T &b){
    	T tmp=a;
        a=b;
        b=tmp;
    }
    void test(){
    	int a=10,b=10;
        //1.自动类型推导,数据类型T必须保持一致,比如下面都是int
        myswap(a,b);
        //2.显示指定
        myswap<int>(a,b);
    }
    //模板必须要确定出T的数据类型
    template<class T>
    void func(){
    }
    void tets(){
    	func<int>();//此时必须显示给出一个数据类型才能使用
    }

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

  1. 普通函数可以发生自动类型转换(隐式类型转换)
  2. 函数模板如果使用自动类型推导,不会发生隐式类型转换
  3. 如果使用显示指定类型会发生隐式类型转换

普通函数和函数模板的调用规则

  1. 如果函数模板和普通函数都有实现,优先调用普通函数

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

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

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

     void myprint(int a,int b){
     	cout<<1<<endl;
     }
     
     template<class T>
     void myprint(int a,int b){
     	cout<<2<<endl;
     }
     
     void test(){
     	myprint<>(a,b);//强制调用函数模板
         char c,d;
     	myprint(c,d);//调用函数模板,虽然普通函数可以类型隐式转换,但麻烦
        //如果函数模板可以产生更好的匹配,优先调用函数模板
     }
    

具体化的函数模板

    template<> bool mycompare(Person &a,Person &b){
    	if(......
    }
    
    

类模板

    template<class NameType,class AgeType>
    class Person{
    public:
    	NameType name;
        AgeType age;
    	Person(NameType name,AgeType age){
        	this->name=name;
            this->age=age;
        }
    }
    void test(){
    	Person<string,int> p1("xx",99);
    }
    

类模板和函数模板的区别

  1. 类模板没有自动类型推导

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

     template<class NameType,class AgeType=int>//年龄默认为int类型
     class Person{
     ...
     }
     
    

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

普通类中的成员函数一开始就创建
类模板中的成员函数在调用时才创建

类模板对象做函数参数

	template<class T1,class T2>//年龄默认为int类型
    class Person{
    ...
    }
	//1.指定传入参数
    void test1(Person<string,int>&p){
    	
    }
    //2.参数模板化
    template<class T1,class T2> 
    void test2(Person<T1,T2>&p){
    	cout<<"t1的类型"<<typeid(T1).name()<<endl;//
    }
	
    //3.整个类模板化
    template<class T>
    void test3(T &p){
    	
    }
    

类模板与继承

    template<class T>
    class base{
    	T m;
    };
    //1. 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型  
    class son1:public base<int>
    {
    	
    };
    //2. 如果不制定,编译器无法给子类分配内存  
	//3. 如果想灵活指定出父类中T的类型,子类也需要变为类模板
    template<class T1,class T2>
    class son2:public base<T2>{
    	T1 m2;
    };

类模板成员函数类外实现

    class Person{
    	Person();
        void showPerson();
    };
    template<class T1,class T2>
    Person<T1,T2>::Person(T1 name,T2 age){
    }
    

类模板分文件编写

  1. 直接包含源文件
  2. 将.h和.cpp中的内容写到一起,后缀名改为.hpp