1-模板
00x1 模板的概念
模板就是建立通用的模具,提高代码的复用性
特点:
- 模板不可以直接使用,它只是一个框架
- 模板的通用并不是万能的
00x2 函数模板
C++另一种编程思想称为泛型编程,主要利用的技术就是模板
学习模板不是为了写模板,而是为了运用STL
C++提供两种模板机制:函数模板和类模板
模板函数
建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表
template<typename T>
函数声明或定义
//template:声明创建模板
//typename:数据类型。可以用class代替
//T:通用的数据类型,名称可以替换,通常为大写字母
定义:
//函数模板的定义
template<typename T>
void mySwap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
使用:
//1、自动推断
mySwap(a,b);
//2、指定类型
mySwap<int>(a,b); //int用于替换T
注意事项:
//1、自动类型推导必须推导出一致的类型
template<typename T>
void swap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
int a=10,b=20;
char c='A';
mySwap(a,c); //错误
mySwap(a,b); //正确
//2、模板必须要确定T的数据类型,才可以使用
template<typename T>
void func()
{
std::cout<<"func"<<std::endl;
}
//func()并没有使用T,调用时编译器报错
func();
//可以把<T>补上,尽管没用
func<int>();
main()函数中不允许声明模板
普通函数与模板函数的区别
- 普通函数可以实现隐式转换
- 模板函数的自动类型推导不能实现隐式类型转换
- 模板函数的指定类型可以实现隐式转换
//举个例子
//普通函数
int Add(int a,int b)
{
return a+b;
}
//模板函数
template<typename T>
T TAdd(T a,T b)
{
return a+b;
}
int a = 10, b= 20;
char c = 'a';
//对于普通函数来说,c只是一个常数
Add(a,b); //正确
Add(a,c); //也正确
//但对于模板函数而言,自动推断时c是char
TAdd(a,b); //正确
TAdd(a,c); //错误
//指定类型则可以实现类型转换
TAdd(a,b); //正确
TAdd(a,c); //也正确
尽量直接指定类型,不要偷懒!
调用规则:
//1、如果普通函数和模板函数都可以调用,则优先调用普通函数
//普通函数
void func(int a,int b)
{
cout<<"普通函数"<<endl;
}
//模板函数
template<typename T>
void func(T a,T b)
{
cout<<"模板函数"<<endl;
}
//重载模板函数
template<typename T>
void func(T a,T b,T c)
{
cout<<"重载模板函数"<<endl;
}
int main()
{
using namespace std;
int a = 10,b =20,c=30;
char d = 'a',e = 'b';
func(a,b); //输出“普通函数”
//func<>(a,b); //输出“模板函数”
func(a,b,c); //输出“重载模板函数”
func(d,e); //输出“模板函数”
}
//如果注释普通函数的实现,则报错,编译器不会自动选择模板函数
//2、可以通过空模板参数列表,强制调用模板函数,如上
//3、模板函数可以发生重载,编译器按参数数量自动选择模板函数
//4、如果模板函数有更好的匹配,优先调用模板函数
局限性
//模板并不是万能
template<typename T>
void func(T a,T b)
{
a = b; //如果a或b是数组,则出错
}
T也不可以是自定义类型,但可以解决
//1、运算符重载
//2、具体化自定义函数
template<>
bool myCopare(person &p1,person &p2)
{
...
}
00x3 类模板
template<class nameType,class ageType> //自定义类型nameType和ageType
class person
{
public:
person(nameType name,ageType age)
{
this->m_name=name; //类的成员变量m_name赋值
this->m_age=age; //类的成员变量m_age赋值
}
void showInfo()
{
cout << "age = " << this->m_age << "name = " << this->name <<endl;
}
nameType m_name;
ageType m_age;
};
int main()
{
person<string,int>p1("小张",24); //实例化对象
p1.showInfo();
return 0;
}
类模板与函数模板的区别
- 类模板中的模板参数列表可以有默认参数
- 类模板使用只能显式指定类型方式
类模板中成员函数创建时机
- 普通类中的成员函数一开始就可以创建
- 类模板中的成员函数在调用时才创建
class Person1
{
public:
void showPerson()
{
cout << "Person1 show" << endl;
}
};
template <class T>
class MyClass
{
public:
T obj;
void func()
{
obj.showPerson1(); //调用showPerson()
}
};
//类模板中的函数只有被调用时才创建,因此 编译 的时候这段代码没有任何问题