目录
1、函数模板:
(1)、普通函数和函数模板的区别:
(2)、普通函数和函数模板同名:
(3)、函数模板的局限性:
(4)、设计一个算法来打印任意数据类型的数组和数组排序
2、类模板:
(1)、类模板概述
(2)、类模板的份文件实现
(3)、类模板作为函数参数
(4)、类模板的派生
1)、类模板派生出普通类
2)、类模板派生出类模板
3、模板类的应用:
函数模板关键字:template
定义:可以把形参的类型抽象化,用虚拟类型T表示,这叫做函数模板,根据实参确定来推到T的类型。
#include
using namespace std;
template
//typename明确T是类型
void test01(T1 &a,T2 &b)
{
T1 temp = a;
a = b;
b = temp;
}
void test02()
{
int a = 10;
int b = 20;
test01(a,b);
cout<
运行结果:
函数模板的意义:为了实现泛型编程,减轻编程的工作量,增强函数的重用性。
函数模板的特性:
1、函数模板本身的编译。
2、调用位置自动推导T的类型,再将函数编译成函数模板(类型替换)。
注意:函数模板在调用时会自动推导T的类型,不会自动类型转换。
swapAllType(10, 'a'); //错误
1、函数模板不允许自动类型转换,在识别变量的类型之后不能改变。
2、普通函数可以进行自动类型转换(形参已经固定的情况下,要注意精度丢失)
优先使用普通函数,如要用函数模板要加<>强制使用
swapALLType<>(a,b)
函数模板的局限性
1、编译时间长
2、难以调试,函数模板在编译的阶段生成
3、可读性差
利用打印出一个对象引出函数模板的局限性:由于cout<<不能直接打印实例化对象,所以可以重载或者采用函数模板特例化 template<>void printALLType
(person ob)。
解决方法:1、函数模板参数具体化;2、重载运算符
函数模板参数具体化:
#include
#include
using namespace std;
//函数模板,在编译阶段执行。
template
void printALLType(T a)
{
cout<<" T = "<< a<< endl;
}
class person
{
friend void printALLType(person ob);
private:
int num;
string name;
public:
person(int num,string name):num(num),name(name)
{
}
~person(){}
};
//函数模板的特例化,相当于实例化一个函数模板来解决问题
//如果直接调用函数模板会出现问题需要重载<<,特例化之后
//我们直接在参数中实例化一个对象
template<> void printALLType(person ob)
{
cout<
思路:
1、函数模板来实现任意数据的打印还有排序。
2、当类数组(数组里面存放的同一个类的不同对象)排序和遍历需要函数重载
//设计一个算法可以打印任意数组类型的数组和排序
//思路函数模板
#include
#include
using namespace std;
class data
{
friend ostream &operator <<(ostream &cout,data &ob);
private:
int a;
public:
data(){}
data(int a):a(a){}
bool operator <(data &ob)
{
return (a
void print(T *arr,int n)
{
for(int i =0;i < n;i++)
{
cout<
void sort(T *arr,int n)
{
for(int i =0;i < n-1;i++)
{
for(int j =0;j < n-i-1;j++)
{
if(arr[j+1] < arr[j])
//如果是类的比较需要重载<
{
T temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
void test01()
{
int arr1[5] = {30,10,50,20,40};
sort(arr1,5);
print(arr1,5);
char arr2[] ="hello world";
sort(arr2,sizeof(arr2));
print(arr2,sizeof(arr2));
//类定义arr3数组创建五个匿名对象,调用初始化列表
data arr3[5] ={data(200),data(300),data(100),data(600),data(500)};
sort(arr3,5);
print(arr3,5);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
运行结果:
将类中的类型抽象化,该类称为函数模板
类模板在实例化的时候必须指定类型 person
ob1(1,2);
#include
#include
using namespace std;
template //类模板,根据成员变量个数决定参数
class person
{
private:
T1 a;
T2 b;
public:
person(){}
person(T1 a,T2 b):a(a),b(b)
{
}
~person(){}
void show()
{
cout<ob1(1,2);
ob1.show();
personob2('a','b');
ob2.show();
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
类模板实例化时,必须指定T1和T2的类型。
注意:构造函数或者成员函数在外部定义他的作用域变成了类名
::
template
person::person(T1 a, T2 b)//类外定义构造函数模板类作用域是person
{
this->a =a;
this->b =b;
}
注意:1、类模板做参数,可以接受任意类型
2、声明友元函数需要加上 template
#include
#include
using namespace std;
template //类模板,根据成员变量个数决定参数
class person
{
friend void show2(person &ob);
template //类模板作为形参.也作为友元函数。
friend void show3(person&ob);
private:
T1 a;
T2 b;
public:
person(){}
person(T1 a,T2 b);
~person(){}
void show1();
};
template
person::person(T1 a, T2 b) //类外定义作用域是person
{
this->a =a;
this->b =b;
}
template
void person::show1() //类外定义作用域是person
{
cout< &ob)
//只能访问类型是int int的类模板
{
cout<//类模板作为形参,可以访问任何类型的类模板
void show3(person&ob)
{
cout<ob1(1,2);
ob1.show1();
personob2('a','b');
ob2.show1();
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
子类实例化的时候需要知道父类是什么类型,也就是具体化父类类型,方便编译器分配子类的内存
template //类模板,根据成员变量个数决定参数
class person
{
private:
T1 a;
T2 b;
public:
person(){}
person(T1 a,T2 b);
~person(){}
};
class boy:public person//继承的时候也得表明是类模板
{
public:
int c;
boy(){}
boy(int a,int b,int c):person(a,b),c(c){}
//子类初始化父类的时候
};
注意:与派生出普通函数的区别就是,在声明式模板类的时候需要加上父类的模板类型
template //模板函数继承模板函数得加上父类的模板类型
class other:public person
{
public:
T d;
other(){}
other(int a,int b,int d):person(a,b),d(d){}
};
设计一个数组模板类,完成对不同类型的元素的管理
myarray.h
#ifndef MYARRAY_H
#define MYARRAY_H
#include
using namespace std;
template
class MyArray
{
template
friend ostream & operator <<(ostream &cout,MyArray &ob);
private:
T *arr;
int capacity;
int size;
public:
MyArray();
MyArray(int capacity);
MyArray(const MyArray &ob);
~MyArray();
void pushBack(T elem);//添加元素
void popBack();//删除元素
int getCapacity();//得到容量的大小
};
template
ostream &operator <<(ostream &cout, MyArray &ob)
{
for(int i =0;i < ob.size;i++)
{
cout<
MyArray::MyArray()
{
size = 0;
capacity = 5;
arr = new T[capacity];
}
template
MyArray::MyArray(int capacity)
{
this->capacity =capacity;
this->size = 0;
arr =new T[capacity];
}
template
MyArray::MyArray(const MyArray &ob)
{
this->capacity =ob.capacity;
this->size =ob.size;
this->arr = new T[capacity];
memcpy(this->arr,ob.arr,size*sizeof(T));
}
template
MyArray::~MyArray()
{
if((this->arr) != nullptr)
{
delete []arr;
arr = nullptr;
}
}
template
void MyArray::pushBack(T elem)
{
if(size == capacity)
{
T *tempArr = new T[2*capacity];
memcpy(tempArr,arr,size*sizeof(T));
delete []arr;
arr =nullptr;
arr = tempArr;
capacity = 2*capacity;
}
arr[size] = elem;
size++;
}
template
void MyArray::popBack()
{
if(size == 0)
{
std::cout<<"数组为空"<
int MyArray::getCapacity()
{
return capacity;
}
#endif // MYARRAY_H
main.cpp
#include
#include
#include"myarray.h"
using namespace std;
class Data
{
friend ostream & operator <<(ostream &out, Data ob);
private:
int a;
public:
Data(){}
Data(int a):a(a){}
};
ostream & operator <<(ostream &out, Data ob)
{
out << ob.a;
return out;
}
int main(int argc, char *argv[])
{
MyArray arr;
arr.pushBack(30);
arr.pushBack(10);
arr.pushBack(40);
arr.pushBack(20);
arr.pushBack(50);
arr.pushBack(70);
cout< arr1;
Data ob(30);
Data ob1(40);
Data ob2(10);
Data ob3(20);
Data ob4(60);
Data ob5(50);
arr1.pushBack(ob);
arr1.pushBack(ob1);
arr1.pushBack(ob2);
arr1.pushBack(ob3);
arr1.pushBack(ob4);
arr1.pushBack(ob5);
arr1.pushBack(Data(80));
cout<
运行结果: