C++模板
泛型编程
泛型是一种可以代替所有类型的通用类型
泛型编程的思想
编写与类型无关的通用代码,提高代码的复用型,其中模板是泛型编程的基础
泛型编程的思想在模板入门后就有更深的体会
模板分为函数模板和类模板
函数模板
写一个函数模板,交换int类型时我们传入int实参,形参就被推导为int类型,传入double,形参就被推导为double,这个推导过程是编译器帮我们做的。
什么是函数模板?
所谓的函数模板,实际上是建立通用函数,他所用到数据的类型(包括返回值类型,形参类型,局部变量类型)可以不具体指定,而是用虚拟的类型来代替(实际上是用一个标识符来占位),等发生函数调用时再根据传入的实参来逆推出真正的类型,这个就是函数模板
#include <iostream>
using namespace std;
#include<string>
template <class T>
void swap(T x, T y)
{
//这个swap()函数只是一个例子,没有实现交换功能,实现交换参数得传引用
cout << "void swap(T x, T y)" << endl;
}
int main()
{
swap(1, 2);
swap(1.0, 2.0);
swap('a', 'b');
return 0;
}
模板的格式
template<class T>
返回类型 函数名(参数列表)//T a
template<typename T> 返回值类型 函数名(参数列表)
小结
函数模板不过是把我们要做的重复的事情交给编译器去做,提高了代码的复用性
模板实例化
什么是函数模板的实例化
推演出T的类型实例化生成具体的函数
实例化分为显示实例化和隐式实例化
隐式实例化:编译器根据实参推演模板参数的具体类型
显式实例化:人为指定某种具体类型
类模板
声明类模板,就可以将类型参数用于类的成员函数和成员变量,换句话,原来使用int,float,char等内置类型的地方,都可以用类型参数来代替
类模板的一般形式:
template<class T>//class可以换成typename 模板头
class 类名
{
函数定义;
};
//多个类型参数和函数模板类似,逗号隔开
当类中成员函数在类外定义时,必须定义为函数模板,带上模板头,定义形式如下:
template <class T>
函数类型 类名<T>::函数名(形参列表)
{
函数体;
}
例如:
template<typename T1, typename T2> // 模板头 没有分号
class Point {
public:
Point(T1 x, T2 y) : x(x), y(y) { }
public:
T1 getX() const; //成员函数后加const,声明该函数内部不会改变成员变量的值
void setX(T1 x);
T2 getY() const;
void setY(T2 y);
private:
T1 x;
T2 y;
};
template<typename T1, typename T2> //模板头
T1 Point<T1, T2>::getX() const {
return x;
}
template<typename T1, typename T2>
void Point<T1, T2>::setX(T1 x) {
x = x;
}
template<typename T1, typename T2>
T2 Point<T1, T2>::getY() const {
return y;
}
template<typename T1, typename T2>
void Point<T1, T2>::setY(T2 y) {
y = y;
}
int main()
{
Point<int, double> p1(66, 20.5);
Point<int, char*> p2(10, "东经33度");
Point<char*, char*> *p3 = new Point<char*, char*>("西经12度", "北纬66度");
cout << "x=" << p1.getX() << ", y=" << p1.getY() << endl;
cout << "x=" << p2.getX() << ", y=" << p2.getY() << endl;
cout << "x=" << p3->getX() << ", y=" << p3->getY() << endl;
return 0;
}
typename和class的区别
在模板引入 c++ 后,采用class来定义模板参数类型,后来为了避免 class 在声明类和模板的使用可能给人带来混淆,所以引入了 typename 这个关键字。
模板定义语法中关键字 class 与 typename 的作用完全一样。
不同的是typename 还有另外一个作用为:使用嵌套依赖类型(nested depended name)