C++的一种编程思想称为泛型编程,用到的技术就是模板
C++提供两种模板:函数模板和类模板。
1.函数模板
1.函数模板作用
建立一个通用函数,其返回值类型和形参类型可以用一个虚拟的类型来代替,提高代码复用性,将类型参数化。
2.语法
template<typename T>
//函数声明或定义
template--声明创建模板
typename--表明其后面的符号是一种数据类型,可以用class代替
T--通用的数据类型,名称可以替换,通常为大写字母
3.例子
未应用模板(代码复杂,通用性差)
void intswap(int& a, int& b)
{
int c;
c = a;
a = b;
b = c;
}
void doubleswap(double& a, double& b)
{
double c;
c = a;
a = b;
b = c;
}
应用模板(代码简洁,通用性强)
注意:函数模板一次只能对应一个函数,也就是说T不能多次重复使用
template<typename T>
void swap(T& a, T& b)
{
T c;
c = a;
a = b;
b = c;
}
4.模板使用方式
1.自动类型推导
swap(a,b);
2.显示指定类型
swap<int>(a,b);
5.注意事项
1.自动类型推导
必须推导出一只的数据类型T才可以使用
反例:
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void swap(T& a, T& b)
{
T c;
c = a;
a = b;
b = c;
}
int main()
{
int a=0;
char b = '12';
swap(a, b);
return 0;
}
2.T的类型必须确定
模板必须要确定T的类型,才可以使用
反例:
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void swap()
{
cout << "swap" << endl;
}
int main()
{
swap();
return 0;
}
6.案例
1.题目
对数组进行降序排序
2.代码
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void sort(T a[],int len)
{
T temp;
int max ;
for (int i = 0; i < len; i++)
{
max = i;
for (int j = i; j < len; j++)
{
if (a[j] > a[max])
{
temp = a[j];
a[j] = a[max];
a[max] = temp;
}
}
}
}
int main()
{
char c[6] = "badce";
sort(c,5);
cout << c << endl;
int a[6] = {4,5,2,3,1};
sort(a, 5);
for(int i=0;i<5;i++)
cout << a[i] << endl;
return 0;
}
3.结果
7.普通模板与函数模板区别
·普通函数可以发生自动类型转换(隐式类型转换)
·函数模板调用时,如果利用自动类型推导,则不会发生隐式类型转换
·如果利用显示指定类型的方式,可以发生隐式类型转换
1.普通函数隐式类型转换
#include<iostream>
using namespace std;
#include<string>
int fun(int a, int b)
{
return a + b;
}
int main()
{
int a = 10;
char c = 'c';//a=97,c=99
cout << fun(a, c) << endl;
return 0;
}
2.自动类型推导不可以使用
#include<iostream>
using namespace std;
#include<string>
template<typename T>
int fun(T a, T b)
{
return a + b;
}
int main()
{
int a = 10;
char c = 'c';
cout << fun(a, c) << endl;
return 0;
}
3.显式指定类型可以使用
#include<iostream>
using namespace std;
#include<string>
template<typename T>
int fun(T a, T b)
{
return a + b;
}
int main()
{
int a = 10;
char c = 'c';
cout << fun<int>(a, c) << endl;
return 0;
}
4.建议
建议使用显式指定类型的方式调用,这种更加明确。
8.普通函数与函数模板调用规则
1.函数模板可以发生重载
1.普通函数与函数模板重载
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{
cout << "函数模板" << endl;
}
void fun()
{
cout << "普通函数" << endl;
}
int main()
{
fun(1);
fun();
return 0;
}
2.函数模板之间的重载
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{
cout << "函数模板" << endl;
}
template<typename T>
void fun(T a,T b)
{
cout << "重载函数模板" << endl;
}
int main()
{
fun(1);
fun(1, 1);
return 0;
}
2.调用优先级
如果普通函数和函数模板都可以调用,优先调用函数模板
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{
cout << "函数模板" << endl;
}
void fun( int a)
{
cout << "普通函数" << endl;
}
int main()
{
fun(1);
return 0;
}
注意:就算普通函数只有一个声明也不会调用函数模板(会报错)。
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{
cout << "函数模板" << endl;
}
void fun(int a);
int main()
{
fun(1);
return 0;
}
3.强制调用模板函数
通过空模板参数列表,强制调用函数模板
fun<>(1);
4.发生隐式类型转换时的优先级
当普通函数发生隐式类型转换时,会优先调用函数模板(程序会使用最优选择)
#include<iostream>
using namespace std;
#include<string>
template<typename T>
void fun(T a)
{
cout << "函数模板" << endl;
}
void fun(char a)
{
cout << "普通函数调用" << endl;
}
int main()
{
fun(1);
return 0;
}
2.类模板
1.定义
建立一个通用类,类中的成员数据类型可以不具体指定,用一个虚拟的类型来代替。
2.语法
template<typename T>
//类
template--声明创建模板
typename--表明其后面的符号是一种数据类型,可以用class代替
T--通用的数据类型,名称可以替换,通常为大写字母
3.例子
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:
person(A name, B age)
{
this->name = name;
this->age = age;
}
void show()
{
cout << this->name << this->age << endl;
}
A name;
B age;
};
int main()
{
person<string, int>p1("孙悟空", 999);
p1.show();
return 0;
}
4.类模板与函数模板区别
1.类模板不可以使用自动类型推导,只能自己设置类型。
2.类模板的模板参数列表中可以默认参数
模板参数表:即为尖括号里面的
template<class A,class B>
默认参数
template<class A,class B=int>
5.类模板中的成员函数创建时机
只要不去调用,就不会创建,所以a.fun()不会报错
#include<iostream>
using namespace std;
#include<string>
template<class A>
class person
{
public:
A a;
void fun()
{
a.fun1();
}
};
int main()
{
return 0;
}
6.类模板对象做函数参数
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:
A name;
B age;
person(A name, B age)
{
this->name = name;
this->age=age;
}
void show()
{
cout << this->name << endl;
cout << this->age << endl;
}
};
void fun(person<string, int>&p1)
{
p1.show();
}
int main()
{
person<string, int>p1("孙悟空", 100);
fun(p1);
return 0;
}
此时的函数参数应该是“person<string, int>&p1”
7.函数模板参数模板化
使用函数模板来提高复用性
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:
A name;
B age;
person(A name, B age)
{
this->name = name;
this->age=age;
}
void show()
{
cout << this->name << endl;
cout << this->age << endl;
}
};
template<class T1,class T2>
void fun(person<T1, T2>&p1)
{
p1.show();
}
int main()
{
person<string, int>p1("孙悟空", 100);
fun(p1);
return 0;
}
1.类型显示方法
如果想显示出自动类型转换的类型是什么,可以用这个方法
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:
A name;
B age;
person(A name, B age)
{
this->name = name;
this->age=age;
}
void show()
{
cout <<"姓名:" << this->name << endl;
cout << "年龄:" << this->age << endl;
}
};
template<class T1,class T2>
void fun(person<T1, T2>&p1)
{
p1.show();
cout <<"T1的类型:" << typeid(T1).name() << endl;
cout <<"T2的类型:" << typeid(T2).name() << endl;
}
int main()
{
person<string, int>p1("孙悟空", 100);
fun(p1);
return 0;
}
8.将做参数的整个类都模板化
#include<iostream>
using namespace std;
#include<string>
template<class A,class B>
class person
{
public:
A name;
B age;
person(A name, B age)
{
this->name = name;
this->age=age;
}
void show()
{
cout <<"姓名:" << this->name << endl;
cout << "年龄:" << this->age << endl;
}
};
template<class T>
void fun(T &p1)
{
p1.show();
cout << "T的数据类型:" << typeid(T).name() << endl;
}
int main()
{
person<string, int>p1("孙悟空", 100);
fun(p1);
return 0;
}
9.类模板与继承
父类如果是一个模板,子类在继承时需要指出他的数据类型
1.手动指定数据类型
#include<iostream>
using namespace std;
#include<string>
template<class T>
class base
{
public:
T a;
};
class son :public base<int>
{
};
int main()
{
return 0;
}
2.将子类也变为模板
#include<iostream>
using namespace std;
#include<string>
template<class T>
class base
{
public:
T a;
};
template<class T1,class T2>
class son :public base<T2>
{
public:
T1 a;
};
int main()
{
son<string, int>p1;
return 0;
}
10.类模板的函数类外实现
1.构造函数的类外实现
#include<iostream>
using namespace std;
#include<string>
template<class T1,class T2>
class person
{
public:
T1 name;
T2 age;
person(T1 name, T2 age);
};
template<class T1,class T2>
person<T1,T2>::person(T1 name,T2 age)
{
this->name = name;
this->age = age;
}
int main()
{
return 0;
}
2.成员函数的类外实现
#include<iostream>
using namespace std;
#include<string>
template<class T1,class T2>
class person
{
public:
T1 name;
T2 age;
person(T1 name,T2 age);
void fun();
};
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>::fun()
{
cout << name << endl;
cout << age << endl;
}
int main()
{
person<string, int>p("埃里给", 18);
p.fun();
return 0;
}
11.类模板分文件编写
该程序包含一个头文件和一个源文件,头文件负责函数实现,源文件负责函数调用
.hpp后缀名:约定俗成的包含类模板的声明与实现。
1.头文件(person.hpp)
#pragma once
#include<iostream>
using namespace std;
#include<string>
template<class T1, class T2>
class person
{
public:
person(T1 name, T2 age);
void show();
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 << endl;
cout << age << endl;
}
2.源文件
#include"person.hpp"
int main()
{
person<string,int>p("埃里给", 18);
p.show();
return 0;
}
3.输出结果
12.类模板与友元
不想写了,想写的时候补上