通俗的讲,模板的作用:一段代码可以适用多个场景。
函数模板格式:
template<模板参数列表>
类型名 函数名(参数列表)
{ 内容 }
模板参数列表有两种:(两者都可以使用)
- tpyename
- class
- template<class T>
- template<typename T>
T 为数据类型,可以为int ,char 等数据类型
1.自动类型推导
2.必须给出数据类型
- template<class T>
- void show(T a,T b)
- {
- cout << a << endl;
- cout << b << endl;
- }
- int main()
- {
- //自动类型推导
- int a = 10;
- int b = 20;
- show(a,b);
- //给出类型也可以使用
- show<int>(a, b);
- 当函数没有参数时,不能使用自动类型推导
- 当函数模板参数类型和模板的参数类型不存在对应关系时,不能使用自动类型推导
与函数模板返回值相关的模板参数不能进行自动推导
自动推导必须从左到右推导,不能间隔
1.当函数模板没有参数时:

2.当函数模板参数类型和模板的参数类型不存在对应关系时

3.与函数模板返回值相关的模板参数不能进行自动推导

4. 自动推导必须从左到右推导,不能间隔

1.普通函数调用时可以发生自动类型转换(隐式类型转换)
2.函数模板调用时,利用自动类型推导,不会发生隐式类型转换
3.利用显示指定类型的方式,可以发生隐式类型转换
4.模板本身不会生成任何目标代码,只有模板生成的实例会生成目标代码
5.函数指针也只能指向模板的实例,不能指向模板本身
6.函数模板应该和函数体一同放到头文件中
1.普通函数调用时可以发生自动类型转换(隐式类型转换)
- //普通函数
- void show(int a,int b)
- {
- cout << a + b << endl;
- }
- int main()
- {
-
- int a = 10;
- char c = 'a';//a=97
- //发生隐式转换 把char类型转换为int 类型
- show(a, c);
- return 0;
- }
2.函数模板调用时,利用自动类型推导,不会发生隐式类型转换
- //模板函数
- template<class T>
- void show(T a,T b)
- {
- cout << a + b << endl;
- }
- int main()
- {
-
- int a = 10;
- char c = 'a';
- //自动类型转换
- //报错 类型不匹配,无法发生隐式类型转换
- show(a, c);
- return 0;
- }
3.利用显示指定类型的方式,可以发生隐式类型转换
- template<class T>
- void show(T a,T b)
- {
- cout << a + b << endl;
- }
- int main()
- {
-
- int a = 10;
- char c = 'a';
- //显示指定类型
- //类型不匹配,但可以发生隐式类型转换
- show<int>(a, c);
- return 0;
- }
1.函数模板和普通函数都可以实现,优先调用普通函数
2.可以通过空模板参数列表来强制调用函数模板
3.函数模板可以发生重载
4.函数模板可以产生更好的匹配,优先使用函数模板
1.函数模板和普通函数都可以实现,优先调用普通函数
- template<class T>
- void show(T a,T b)
- {
- cout << a + b << endl;
- cout << "函数模板的调用" << endl;
- }
- void show(int a, int b)
- {
- cout << a + b << endl;
- cout << "普通函数的调用" << endl;
- }
- int main()
- {
- int a = 10;
- int b = 20;
- show(a, b);
- return 0;
- }

2.可以通过空模板参数列表来强制调用函数模板
- template<class T>
- void show(T a,T b)
- {
- cout << a + b << endl;
- cout << "函数模板的调用" << endl;
- }
- //当普通函数有声明未实现时
- void show(int a, int b);
- int main()
- {
- int a = 10;
- int b = 20;
- //通过空模板列表强制调用函数模板
- show<>(a, b);
- return 0;
- }

3.函数模板可以发生重载
- template<class T>
- void show(T a,T b)
- {
- cout << a + b << endl;
-
- }
- //函数模板重载
- template<class T>
- void show(T a, T b, T c)
- {
- cout << a + b + c << endl;
- }
-
- int main()
- {
- int a = 10;
- int b = 20;
- int c = 30;
- show(a, b);
- //重载使用
- show(a, b, c);
- return 0;
- }
4.函数模板可以产生更好的匹配,优先使用函数模板
- template<class T>
- void show(T a,T b)
- {
- cout << a << endl;
- cout << b << endl;
- cout << "函数模板的调用" << endl;
- }
- //普通函数
- void show(int a,int b)
- {
- cout << a << endl;
- cout << b << endl;
- cout << "普通函数的调用" << endl;
- }
-
- int main()
- {
- char a = 10;
- char b = 20;
- show(a, b);
-
- return 0;
- }

1.当数据类型为自定义数据类型时可能不适用
2.当数据为一个数组时可能也不适用
类模板格式:
template<class/typename T,...>
class 类名
{
}
1.类模板没有自动类型推导
2.类模板可以有默认数据类型
- template<class T>
- class person
- {
- perosn();
- T a;
- };
-
- int main()
- {
- //报错 不能自动类型推导
- person p;
- //必须给出数据类型
- person<int>p1;
- return 0;
- }
- template<class T=int>//可以有默认参数
- class person
- {
- perosn();
- T a;
- };
-
- int main()
- {
- //有默认参数可以不给出数据类型
- person<>p1;
- return 0;
- }
1.普通类的成员函数在调用前就已经创建
2.类模板的成员函数在调用前才创建
- 指定传入类型
- 参数模板化
- 类模板化
- template<class T1,class T2>
- class person
- {
- public:
- person(T1 a, T2 b)
- {
- this->age = a;
- this->name = b;
- }
- T1 age;
- T2 name;
- };
- //1.传入指定参数
- void show(person<int,string>&p)
- {
- cout << p.age << endl;
- cout << p.name << endl;
- }
- //2.参数模板化
- template<class T1,class T2>
- void show1(person<T1,T2>&p)
- {
- cout << p.age << endl;
- cout << p.name << endl;
- }
- //3.类模板化
- template<class T>
- void show2(T &p)
- {
- cout << p.age << endl;
- cout << p.name << endl;
- }
- int main()
- {
- person<int, string>p1(10,"wang");
- show(p1);
- show1(p1);
- show2(p1);
- return 0;
- }
- template<class T1,class T2>
- class person
- {
- public:
- person(T1 a, T2 b)
- {
- this->age = a;
- this->name = b;
- }
- T1 age;
- T2 name;
- };
- //继承时需要指定数据类型
- class son :public person<int,string>
- {
-
- };
- template<class T1,class T2>
- class person
- {
- public:
- person(T1 a, T2 b)
- {
- this->age = a;
- this->name = b;
- }
- T1 age;
- T2 name;
- };
- //子类也为类模板
- template <class T1,class T2,class T3>
- class son :public person<T1,T2>
- {
- public:
- T1 age;
- T2 name;
- };
- //类模板
- template<class T1,class T2>
- class person
- {
- public:
- person(T1 a, T2 b)
- {
- this->age = a;
- this->name = b;
- }
- //成员函数
- void show();
- T1 age;
- T2 name;
- };
- //成员函数类外实现 需要添加类模板格式
- template <class T1,class T2>
- void person::show()
- {
- cout << age << end;
- cout << name << endl;
- }
2.分文件编写 (统一创建一个 .hpp文件)
第一种:.h定义 .cpp实现
第二种:定义和实现放到一个 .hpp中(名称并非固定)
.hpp代码:
- #include<iostream>
- using namespace std;
- template<class T>
- class person
- {
- public:
- person(T a1);
- void show();
- T a;
- };
- template<class T>
- person::person(T a1)
- {
- this->a = a1;
- }
- template<class T>
- void person::show()
- {
- cout << a << endl;
- }
在主函数中创建一个person对象
- #include<iostream>
- #include<string>
- #include"源1.hpp"
- using namespace std;
-
- int main()
- {
- //创建一个person对象
- person<int> p(10);
- return 0;
- }
一般都会选择类内声明和实现
1.友元函数在类内实现
- template<class T>
- class person
- {
- //1.全局函数类内实现
- friend void set_age(person<T>&p, T a)
- {
- p.age = a;
- }
- public:
- person(T a)
- {
- this->age = a;
- }
- T get_age()
- {
- cout << age << endl;
- return age;
- }
- private:
- T age;
- };
- int main()
- {
- person<int>p(20);
- set_age(p, 30);
- p.get_age();
- return 0;
- }
2.友元函数类外实现
- //需要让友元函数提前知道person
- template <class T>
- class person;
- //需要让编译器提前知道该友元函数
- template<class T>
- void set_age(person<T>&p, T a)
- {
- p.age = a;
- }
-
- template<class T>
- class person
- {
- //函数类内声明
- //需要添加空模板参数列表<>
- friend void set_age<>(person<T>&p, T a);
- public:
- person(T a)
- {
- this->age = a;
- }
- T get_age()
- {
- cout << age << endl;
- return age;
- }
- private:
- T age;
- };
-
- int main()
- {
- person<int>p(20);
- set_age(p, 30);
- p.get_age();
- return 0;
- }
类模板中可以定义静态成员,从该类模板实例化得到的所有类都包含同样的静态成员。
- template <class T1>
- class person
- {
- public:
- T1 a;
- static int b;
- };
- template<> int person<int>::b = 10;
- int main()
- {
- person<int>p1;
- person<int>p2;
- cout << p1.b << endl;
- cout << p2.b << endl;
- return 0;
- }
