模板:所谓模板就是建立通用的摸具,大大提高复用性
模板的特点:
函数模板的作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表
语法:
template<typename T>
函数声明或定义
例子:
template<typename T>
void swap(T &a, T &b)
{
T temp = a;
a = b;pp
b = temp
}
解释:
template ---- 声明创建模板
typename ---- 表明后边的符号是一种数据类型,可以用class代替
T ---- 通用的数据类型,名称可以替换,通常为大写字母
总结:
函数模板利用关键字template
使用函数模板有两种方式:
1、自动类型推导
调用:例:函数名(a, b)
2、显示指定类型
调用:例:函数名
模板的目的是为了提供复用性,将类型参数化
注意:
三个区别:
总结:
因以上的差别,所以推荐在调用函数模板时要使用指定类型的方式,清楚明了
规则:
函数名<>(参数1, 参数)
局限性:模板的通用性并不是万能的,对于一些特定的数据类型,或自定义的数据类型,不做处理很难实现。
比如:普通赋值操作函数,传入的参数为数组类型或者为自定义类型时无法实现函数功能
解决方法:
1、运算符重载
2、具体化参数模板(在原有的函数模板后,加上具体类型模板) 语法:template<> 返回类型 函数名(具体类型 参数1, 具体类型 参数2){}
总结:
类模板的作用:
建立一个通用类,类中成员的数据类型可以不具体确定,用一个虚拟的类型来代表
语法:
template<class T>
class 类名{}
示例:
#include
using namespace std;
template<class AgeTpye, class NameTpye>
class Person
{
public:
AgeTpye age;
NameTpye name;
Person(AgeTpye age, NameTpye name)
{
this->age = age;
this->name = name;
}
void show()
{
cout << this->name << endl;
cout << this->age << endl;
}
};
int main()
{
Person<int, string>p(15, "张三");
p.show();
return 0;
}
主要有两点区别:
template
类模板中的成员函数和普通类中的成员函数区别:
示例:
#include
using namespace std;
class Person1
{
public:
void showperson1()
{
cout << "调用了showperson1" << endl;
}
};
class Person2
{
public:
void showperson2()
{
cout << "调用了showperson2" << endl;
}
};
template<class T>
class Person
{
public:
T obj;
void fun1()
{
obj.showperson1();
}
void fun2()
{
obj.showperson2();
}
};
int main()
{
Person<Person2>p;
p.fun1();
//p.fun2(); //会出错因为实例化对象时指定的类型为Person1
return 0;
}
含义:类模板实例化出的对象,向函数传参的方式
一般有三种传参方式:
后两者方法相当于类模板结合函数模板使用
示例:
#include
using namespace std;
template<class T1, class T2>
class Person
{
public:
T1 name;
T2 age;
Person(T1 name, T2 age)
{
this->age = age;
this->name = name;
}
void showPerson()
{
cout << this->name << endl;
cout << this->age << endl;
}
};
//1、指定传入类型
void printPerson1(Person<string, int> & p)
{
p.showPerson();
}
//2、参数模板化
template<class T2, class T1>
void printPerson2(Person<T2, T1>& p)
{
p.showPerson();
}
//3、把整个类都模板化
template<class T>
void printPerson3(T & p)
{
p.showPerson();
}
int main()
{
Person<string, int>p1("张三", 18);
printPerson3(p1);
return 0;
}
总结:
当类模板碰到继承时,需要注意一下几点:
1、当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
2、如果不指定,编译器无法给子类分配内存
3、如果想灵活指定出父类中T的类型,子类也需变为类模板
方法:
在类内声明成员函数,在类外实现成员函数内容,在添加作用域时需要加上模板的参数列表。
示例:
#include
using namespace std;
template<class T1, class T2>
class Person
{
public:
T1 name;
T2 age;
Person(T1 name, T2 age);
void showPerson();
};
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->age = age;
this->name = name;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
cout << this->age << endl;
cout << this->name << endl;
}
int main()
{
return 0;
}
存在问题:
因为类模板中的成员函数的创建时机是在调用阶段,而份文件编写类时,在.h文件中存放类的属性和成员函数声明,在.cpp文件中实现成员函数的实现。而在调用主cpp时只包含.h文件,在调用时因为.cpp中的函数都没有创建,编译器只看到了.h文件中的函数声明,所以会引发异常
解决方法:
全局函数类内实现:直接在类内声明友元即可
全局函数类外实现:需要提前让编译器知道全局函数的存在和类模板的存在