1、引言
在写排序算法时,若是要写一个交换两个数据的函数,因为基本数据类型有int、float、double等等类型,因此针对每种数据类型可能咱们要写不少swap函数,这些函数除了传入的数据类型不一样,函数体结构大体相同。因此C++为了不让程序员写不少大量重复代码,设计了一种叫作“模板”的东西。咱们写程序时,先不指定什么类型,在调用时咱们再说明一下是什么类型,具体怎么实现接着往下看。程序员
2、函数模板
一、定义
像开头所说,若是要对int、double类型的两个数进行交换咱们要写两个函数,但用函数模板时只须要写一个函数便可。模板定义以下:算法
template <typename T>
或者函数
template <class T>
其中,template是声明一个模板,typename是声明一个虚类型T,这个T能够代替int、double等基本数据类型,那为何还有class?由于最初是用class声明一个T来表示通用数据类型,但考虑到class会和“类”混淆,就改用typename进行定义,同时保留了class,这二者效果相同,但我我的比较习惯用class。this
在进行声明模板以后下面就开始写模板的函数体了,例如交换函数,合起来就是:设计
template <class T>
void swap(T *p1,T *p2){
T temp=*p1;
*p1=*p2;
*p2=temp;
}对象
这样就是一个完整的函数模板排序
二、调用
有两种方式使用模板继承
(1)自动类型推导:编译器会自动断定你传入的数据是什么数据类型,而后将T改为对应数据类型进行操做;内存
(2)本身声明数据类型进行调用,具体实现以下:编译器
//一、自动类型推导
swap(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
//二、显示指定类型
swap<int>(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
什么时候必须本身声明数据类型呢?
那就是没有参数传递的时候。好比知识一个打印函数,没有参数传递,这里就不写代码了。
三、多个虚类型
前面是针对一个函数里面都是同一数据类型的,若是含有不一样数据类型,假若有两个:
template<class T1,class T2>
void func(T1 a,T2 b){....}
1
2
调用时能够自动识别类型也能够本身声明数据类型:
func<int,double>(1,3.14);
1
3、类模板
前面已经介绍了模板大体的做用,这里对类模板就不作过多说明,直接上干货:
一、定义
咱们定一个学生类
template<class T1,class T2,class T3>
class Student{
public:
Student(T1 name,T2 age,T3 score){
..........
}
T1 m_Name;
T2 m_Age;
T3 m_Score;
}
二、调用
调用时必须指定输入了什么数据,也就是尖括号不能省略,这点与函数模板不同
Student<string,int,float>s("Tom",18,85.5);
1
4、类的函数模板
在类内定义的话就跟前面的函数模板同样,若是在类外定义,类外也要写上函数模板的形式:
template<class numType>
class Compare{
public:
Compare(numType a,numType b){
this->a=a;
this->b=b;
}
//声明模板函数:
numType max( );
private:
numType a;
numTypr b;
}
//类外定义模板函数
template<class numType>
numType Compare::max( ){
return this->a>this->b?this->a:this->b;
}
5、类做为数据类型传入
//定义Person1
class Person1 {
public:
void showPerson1() {
cout << "Person1 show" << endl;
}
};
//定义Person2
class Person2 {
public:
void showPerson2() {
cout << "Person2 show" << endl;
}
};
//定义类模板
template<class T>
class MyClass {
public:
T obj;
//类模板中的成员函数
void func1() {
obj.showPerson1();
}
void func2() {
obj.showPerson2();
}
};
//主函数
int main() {
MyClass<Person1>m;
m.func1();
//m.func2();//会报错,由于“showPerson2”: 不是“Person1”的成员
system("pause");
return 0;
}
6、类模板与继承
若是父类是一个模板,子类继承父类模板的时候,不知道父类模板内存是多少,编译器就没法给子类分配内存,解决方案是给子类也加上模板,方案以下:
template<class T>
class Base {
T m_Name;
};
//class Son :public Base { //错误,必须知道T的内存才能指定空间
class Son1:public Base<int>{ // 不灵活
};
//想要灵活指定父类中T的类型
template<class T1,class T2>
class Son2 :public Base<T2> {
public:
T1 m_A;
};
int main() {
//让子类的T为string,子类的T1为int
Son2<int, string>s2;
system("pause");
return 0;
}
7、类模板与友元
前面也有过传入类对象到函数里面,若是这个函数须要用到对象里面的数据,而该数据有被设定为private(私有)就没法直接访问,此时又要用到友元函数的知识:
注意:类内添加友元函数后,若是没有对该友元函数进行声明,编译器认为你没有这个函数,会进行报错。
//先声明类和函数,防止编译器报错
template<class T1,class T2>
class Person;
template<class T1, class T2>
void printPerson(Person<T1, T2> p);
template<class T1,class T2>
class Person {
//全局函数类外实现的声明
friend void printPerson<>(Person<T1, T2> p);
public:
Person(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
//全局函数类外实现
template<class T1,class T2>
void printPerson(Person<T1, T2> p) {
cout << "Name:" << p.m_Name << endl;
cout << "Age:" << p.m_Age << endl;
}
以为有用记得顶一下哦_