模板与泛型编程
模板
概念:建立通用模具,大大提高复用性,利用模板进行编程的思想被称为泛型编程
机制:函数模板与类模板
函数模板
建立一个通用函数,返回值类型与形参类型可以不具体指定,用虚拟类型代表
语法
template:声明创建模板
typename:表示后面的符号是一种数据类型
T:通用数据类型,名称可以替换,但通常是大写字母
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> using namespace std;template <typename T> void swapt (T &a, T &b) { T temp = a; a = b; b = temp; } int main () { int a = 20 ; int b = 10 ; swapt (a,b); swapt <int >(a,b); cout << a << " " << b; }
注意
与普通函数的区别
普通函数调用可以发生隐式类型转换
函数模板使用自动类型推导时不可以发生隐式类型转换
使用显式指定类型时可以发生隐式类型转换
调用规则
普通函数与函数模板都可以实现时,优先调用普通函数
可以通过空模板参数列表来强制调用函数模板
函数模板也可以发生重载
如果函数模板可以产生更好的匹配,则优先调用函数模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <iostream> using namespace std;void print (int a, int b) { cout <<"普通函数调用" <<endl; cout << a <<" " << b << endl; } template <typename T>void print (T a, T b) { cout <<"函数模板调用" <<endl; cout << a <<" " << b << endl; } template <typename T>void print (T a, T b, T c) { cout <<"重载函数模板调用" <<endl; cout << a <<" " << b <<" " <<c << endl; } int main () { int a = 10 ; int b = 10 ; print (a,b); char c = '1' ; char d = '2' ; print (c,d); print<>(a,b); int e = 10 ; print (a, b, e); }
类模板
建立一个通用类,类中的成员数据类型可以用虚拟类型代表
语法
template:声明创建模板
typename:表示后面的符号是一种数据类型
T:通用数据类型,名称可以替换,但通常是大写字母
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> using namespace std;template <class NameType , class AgeType >class person {public : person (NameType name, AgeType age){ this ->age = age; this ->name = name; } void show () { cout <<"name: " <<this ->name<<endl; cout <<"age: " <<this ->age<<endl; } NameType name; AgeType age; }; int main () { person<string, int > p1 ("Jack" , 18 ) ; p1.show (); }
与函数模板的区别
类模板没有自动类型推导的方式
不能写person p("a", 1);这种写法,只能显式指定
类模板在模板参数列表中可以有默认参数
template<class NameType, class AgeType = int>可以指定默认的数据类型
创建时机
普通类中的成员函数一开始就可以创建
类模板中的成员函数在调用时才创建,因为调用时才能确定数据类型
类模板对象做函数参数
传入方式:
指定传入类型:直接显示对象的数据类型
参数模板化:将对象中的参数变为模板进行传递
整个类模板化:将这个对象类型模板化进行传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> using namespace std;template <class NameType , class AgeType >class person {public : person (NameType name, AgeType age){ this ->age = age; this ->name = name; } void show () { cout <<"name: " <<this ->name<<endl; cout <<"age: " <<this ->age<<endl; } NameType name; AgeType age; }; void printp1 (person<string, int > &p) { p.show (); } template <class T1, class T2>void printp2 (person<T1, T2> &p) { cout <<"T1: " <<typeid (T1).name ()<<endl; cout <<"T2: " <<typeid (T2).name ()<<endl; p.show (); } template <class T>void printp3 (T &p) { cout <<"T: " <<typeid (T).name ()<<endl; p.show (); } int main () { person<string, int > p ("Jack" , 18 ) ; printp1 (p); printp2 (p); printp3 (p); }
类模板与继承
模板特化
有些特定数据类型需要一些特定的实现方式,需要具体化实现
函数模板特化
在需要特化的函数前添加template<>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <iostream> using namespace std;class person {public : person (string name, int age){ this ->age = age; this ->name = name; } string name; int age; }; template <typename T>bool cmp (T &a, T &b) { if (a==b){ return true ; } else { return false ; } } template <> bool cmp (person &p1, person &p2) { if (p1.name==p2.name&&p1.age ==p2.age) return true ; else return false ; } int main () { person p1 ("Jack" , 10 ) ; person p2 ("Jack" , 10 ) ; if (cmp (p1,p2)){ cout <<"a==b" <<endl; } else { cout <<"a!=b" <<endl; } }
类模板成员函数类外实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <iostream> using namespace std;template <class NameType , class AgeType >class person {public : person (NameType name, AgeType age); void show () ; NameType name; AgeType age; }; template <class NameType , class AgeType >person<NameType, AgeType>::person (NameType name, AgeType age){ this ->age = age; this ->name = name; } template <class NameType , class AgeType >void person<NameType, AgeType>::show (){ cout <<"name: " <<this ->name << endl; cout <<"age: " <<this ->age<<endl; } int main () { person<string, int > p ("Jack" , 18 ) ; p.show (); }
类模板分文件编写
由于类模板中成员函数在调用时才创建,这导致了分文件编写时链接不到,有两个方法
直接引入.cpp文件
将声明和实现写在同一个文件中,改后缀名为.hpp
常用第二种
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #pragma once #include <iostream> using namespace std;template <class NameType , class AgeType >class person {public : person (NameType name, AgeType age); void show () ; NameType name; AgeType age; }; template <class NameType , class AgeType >person<NameType, AgeType>::person (NameType name, AgeType age){ this ->age = age; this ->name = name; } template <class NameType , class AgeType >void person<NameType, AgeType>::show (){ cout <<"name: " <<this ->name << endl; cout <<"age: " <<this ->age<<endl; }
(hpp文件)
1 2 3 4 5 6 7 8 9 #include <iostream> using namespace std;#include "person.hpp" int main () { person<string, int > p ("Jack" , 18 ) ; p.show (); }
(调用文件)
类模板与友元
使用场景
全局函数类内实现:直接类内声明友元
全局函数类外实现:需要提前让编译器知道全局函数的存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> using namespace std;template <class NameType , class AgeType >class person ;template <class NameType, class AgeType>void printPerson2 (person<NameType, AgeType> p) ;template <class NameType , class AgeType >class person { friend void printPerson (person<NameType, AgeType> p) { cout <<"name: " <<p.name << endl; cout <<"age: " <<p.age<<endl; } friend void printPerson2<>(person<NameType, AgeType> p); public : person (NameType name, AgeType age){ this ->age = age; this ->name = name; } private : NameType name; AgeType age; }; template <class NameType, class AgeType>void printPerson2 (person<NameType, AgeType> p) { cout << "name: " << p.name << endl; cout << "age: " << p.age << endl; } int main () { person<string, int > p ("Jack" , 18 ) ; printPerson (p); printPerson2 (p); }