目录
1类模板(语法规则)
template<class T1,class T2>
class className{
public:
T1 arg1;
T2 arg2;
//....
};
template<class T1,class T2>
class Person{
private:
T1 names;
T2 age;
public:
Person(T1 name,T2 age);
};
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age){
this->names = name;
this->age = age;
}
务必要注意模板类的作用域范围。
在类外进行实现的时候,需要针对类的作用域继续声明:
Person<T1,T2>
2对象的创建
隐式创建
Person<int,QString> p1(12,"name");
需要声明参数的具体类型
3类模板做函数参数
现在有类Person
template<class T1,class T2>
class Person{
public:
Person(T1 name,T2 age);
T1 name;
T2 age;
};
一共有三种方式,来使用类模板做参数
//指定传入类型
void doWork(Person<QString,int> & p){
qDebug()<<"指定传入类型:"<<"Person object's name"<<p.name<<" Person object's age"<<p.age;
//....
}
//参数模板化
template<class T1,class T2>
void doWork2(Person<T1,T2> & p){
qDebug()<<"参数模板化:"<<"Person object's name"<<p.name<<" Person object's age"<<p.age;
//....
}
//整体类型化
template<class T>
void doWork3(T & p){
qDebug()<<"参整体类型化:"<<"Person object's name"<<p.name<<" Person object's age"<<p.age;
//....
}
三种方式,逐渐抽象
示例1:
Person<QString,int> p("name",12);
doWork(p);
doWork2(p);
doWork3(p);
输出:
示例2:
Person<int,QString> p2(12,"name");
doWork2(p2);
doWork3(p2);
输出:
从示例中可以看到,dowork3其实并不知道参数是什么具体类型,但是编译过程中并没有报错,只要调用的时候传入了正确的参数,依旧是可以完美执行的,关于模板函数的创建时间,可以理解为运行时绑定。
4类模板分文件编写
因为类模板函数是在运行时绑定的,如果在Person.h中声明相关变量及函数,在Person.cpp中进行实现。
那么,如果要使用类模板的各类接口,例如在client.cpp中调用,仅仅包含Person.h是不够的(会报错,表示接口未定义,因为具体的实现是要在运行时才绑定,编译时并不会将声明和实现结合),是要包含Peron.cpp的。
一般很少这么写,解决方法,就是全部写在.h中,类内声明,类外实现,并将.h改名为.hpp。
//.hpp
template<class T1,class T2>
class Person{
T1 name;
T2 age;
public:
Person(T1 name,T2 age);
void showItem();
};
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>::showItem(){
qDebug()<<"name:"<<name<<"age:"<<age;
}
5类模板的继承问题
子类继承于类模板,必须指定类模板的具体类型
固定类型:
template<class T1,class T2>
class Person{
T1 name;
T2 age;
public:
Person(T1 name,T2 age);
void showItem();
};
//继承时必须指定类型,否则无法分配空间
class B :public Person<QString,int>{
};
灵活类型:
template<class T1,class T2>
class C : public Person<T2>{
T1 item;
};
//.......
C<int,double> c;
//其中,父类的具体类型为double,而item类型为int
6友元
template<class T1,class T2>
class Person{
private:
T1 name;
T2 age;
friend void printPerson(Person<QString,int> & p){
qDebug()<<"姓名:"<<p.name<<"年级:"<<p.age;
}
public:
//...
};
7应用
编写一个数组
#include <QWidget>
template<class T>
class myArray
{
public:
//构造函数
explicit myArray(int capacity){
this->m_Capacity = capacity;
this->m_Size = 0;
this->pAddress = new T[capacity];
}
//构造函数
myArray(const myArray & array){
this->m_Capacity = array.m_Capacity;
this->m_Size = array.m_Size;
this->pAddress = new T[array.m_Capacity];
for(int i= 0;i<this->m_Size;++i){
this->pAddress[i] = array[i];
}
}
//析构函数
~myArray(){
if(this->pAddress != nullptr){
delete this->pAddress;
this->pAddress = nullptr;
}
}
//等号重载
myArray & operator =(myArray & array){
//
if(this->pAddress != nullptr){
delete this->pAddress;
this->pAddress = nullptr;
}
this->m_Capacity = array.m_Capacity;
this->m_Size = array.m_Size;
this->pAddress = new T[array.m_Capacity];
for(int i= 0;i<this->m_Size;++i){
this->pAddress[i] = array[i];
}
}
//访问重载
T & operator[](const int index){
return this->pAddress[index];
}
//尾插
void push_back(const T & value){
this->pAddress[this->m_Size++] = value;
}
//获取数组大小
int getSize(){
return this->m_Size;
}
//获取数组容量
int getCapacity(){
return this->m_Capacity;
}
private:
int m_Size;
int m_Capacity;
T * pAddress;
};
应用情况:
myArray<int> arr(100);
for(int i= 0;i<10;++i){
arr.push_back(i+1);
}
qDebug()<<arr.getCapacity()<<arr.getSize();
for(int i = 0;i<10;++i){
qDebug()<<arr[i];
}
输出:
可以创建任意类型的数组,STL的底层也是这样实现的
myArray<QString> arr(100);
for(int i= 0;i<10;++i){
QString val = QString::number(i+1);
arr.push_back(val);
}
qDebug()<<arr.getCapacity()<<arr.getSize();
for(int i = 0;i<10;++i){
qDebug()<<arr[i];
}