C++学习笔记
----模板
一.模板的概念
- 在定义函数时把函数参数的类型用同一个类型形参来表示,用一个统一的函数来代替多个相似的函数。模板的本质就是把数据类型参数化,体现了面向对象程序设计的多态性。
- 模板不占用内存也不可执行,模板必须实例化才能产生一个具体可执行的函数。模板不会节省内存空间,是否使用模板生成的文件大小一样。
二.函数模板与模板函数
- 函数模板表示的是对不同数据类型数据进行相同处理的一类函数。
template <class 模板形参1, class 模板形参2,...>
返回类型 函数名(参数表){
...
}
- 函数模板形参表中每个模板类型前都必须有class关键字
- 函数模板的函数参数表中一定要有模板形参类型的参数,不能仅仅用类型形参表示函数的返回类型
template <class T>
T max(T &n1, T &n2){
return (n1>n2) ? n1 : n2;
}
- 函数模板经实例化而生成的具体函数称为模板函数。实参类型与模板类型形参结合规则为:
- 如果函数调用语句实参正好与某个同名函数的参数精确匹配,则生成直接调用该函数的指令,否则查找与函数名同名的函数模板;
- 如果同名的函数模板的参数是匹配的,则用实参类型作为函数模板的类型形参对模板实例化成一个模板函数并生成调用指令,否则查找同名的其它非模板函数;
- 如果其它非模板函数的参数经隐式类型转换后与实参相匹配,则生成调用指令否则会出现编译错误。
int n1=1, n2=2;
max(n1, n2);
#include <iostream>
using namespace std;
template <class T>
T max(T &n1, T &n2){
return (n1>n2) ? n1 : n2;
}
int main(){
int n1=1, n2=2;
cout << "1 ? 2 = " << max(n1, n2) << endl;
float n1_=1.1, n2_=2.2;
cout << "1.1 ? 2.2 = " << max(n1_, n2_) << endl;
char n1__='a', n2__='A';
cout << "a ? A = " << max(n1__, n2__) << endl;
return 0;
}

三.类模板与模板类
- 在类的定义中将类中的数据成员的类型,成员函数的参数的类型,成员函数的返回值的类型都用模板类型形参表示,构成了一个代表多个类的类模板。
class 模板类型形参1 中的class可以改为typename
template <class 模板类型形参1, class 模板类型形参2,...>
class 类模板名{
...
};
- 类模板的声明与实现不能像普通类那样可以分别放在.h和.cpp两个不同的文件中;
- 可以按照先右后左的顺序为类模板的类型形参设置缺省类型,class模板类型形参=缺省类型;
- “类模板名<模板类型形参列表>”构成一个类模板类型,用于表示成员函数的作用域;
- “类模板名<模板类实参列表>”表示一个具体的模板类类型,用于定义类对象
#include <iostream>
using namespace std;
template <class T>
class CMax{
private:
T n1, n2;
public:
CMax(T n1_, T n2_):n1(n1_),n2(n2_){ }
T CompareToMax(){ return (n1>n2) ? n1 : n2; }
};
int main(){
int i1=1, i2=2;
CMax<int> IMax(i1, i2);
cout << "1 ? 2 = " << IMax.CompareToMax() << endl;
float f1=1.1, f2=2.2;
CMax<float> FMax(f1, f2);
cout << "1.1 ? 2.2 = " << FMax.CompareToMax() << endl;
char c1='a', c2='A';
CMax<char> HMax(c1, c2);
cout << "a ? A = " << HMax.CompareToMax() << endl;
return 0;
}

- 如果在类的外部定义类模板中的成员函数,则必须采用类似函数模板的格式,其中成员函数的类作用域改用类模板类型的描述符表示:
template <class 模板类型形参1, 模板类型形参2,...>
返回类型 类模板名<模板类型形参1, 模板类型形参2,...>::成员函数名(参数表){
...
};
template <class T>
class CMax{
private:
T n1, n2;
public:
CMax(T n1_, T n2_):n1(n1_),n2(n2_){ }
T CompareToMax();
};
template <class T>
T CMax<T>::CompareToMax(){
return (n1>n2) ? n1 : n2;
}
- 由于类模板中的模板类型形参不确定,故不能直接定义类模板定义对象,而是要用类模板类型描述符作为类名来定义类对象。类模板类型描述符就是用指定的实际类型对类模板实例化生成一个具体的模板类。
类模板名 <实际类型参数列表> 类对象名(构造函数参数);
- 定义一个类模板的指针和引用不会引起类模板的实例化;
- 类模板成员函数本身也是一个模板,类模板被实例化时它并不自动被实例化,只有当它被调用才被实例化。
CMax<int> IMax(i1, i2);
CMax<float> FMax(f1, f2);
CMax<char> HMax(c1, c2);
- 类模板也可以作为基类,此时派生类可以定义成类模板,也可以在派生类中用具体类型代替基类的模板类型形参使得派生类成为一个普通的类。如果要将派生类也定义成为类模板,则需要在派生类的模板类型形参列表中加入基类的所有模板类型形参并按以下格式定义派生类:
template <class 派生类模板类型形参, class 基类模板类型形参>
class 派生类模板名:继承方式 基类模板名<不带class的基类模板类型形参>{
...
};
#include <iostream>
using namespace std;
template <class T>
class CPoint{
protected:
T x, y;
public:
CPoint(T x_, T y_):x(x_), y(y_){ }
};
template <class t, class T>
class CCircle: public CPoint<T>{
private:
t r;
public:
CCircle(T x_, T y_, t r_):CPoint<T>(x_, y_){ r=r_; }
void print(){
cout << "(" << x << ", " << y << "), r = " << r << endl;
}
};
int main(){
int x1=1, y1=2, r2=3;
float x2=1.1, y2=2.2, r1=3.3;
CCircle<float, int> c1(x1, y1, r1);
c1.print();
CCircle<int, float> c2(x2, y2, r2);
c2.print();
return 0;
}
