1、普通函数与模板函数调用原则
- 函数模板可以像普通函数一样被重载;
- 当函数模板和普通函数都符合条件时,编译器优先考虑普通函数;
- 但如果函数模板产生一个更好的匹配,则选择函数模板;
- 可以通过空模板实参列表的语法,限制编译器只通过模板匹配;使用类型列表, max<>(a,b),强制要求使用函数模板;
- 当都不满足类型条件时,会调用普通函数;因普通函数的调用,可以进行隐式的类型转换;函数模板的调用,使用类型参数化,严格按照类型进行匹配,不会进行类型的自动转换;
函数模板本质:
- 编译器中的汇编,根据函数模板帮程序员生成 不同类型 函数;
- 具体是进行两次编译:在声明时对模板代码本身进行编译,在调用时对参数替换后的代码进行编译;
- 函数模板可以和普通函数一样发生重载;
2、模板类的派生
需要具体化模板类,知道父类的数据类型,才知道如何分配内存。
class B : public A<int> { public: B(int a, int b) :A<int>(a)//类模板派生需要重新定义构造函数 { } private: int b; };
3、类模板函数
在类外声明,友元函数在类外声明(友元函数只用于输入输出的运算符重载,不可用于其他函数)
如果分开写,函数实现在另一个文件时,类模板函数需要包含 .cpp 文件。
#include <iostream> #include <typeinfo> using namespace std; template <typename T> class Complex { // 对于友元函数,类模板的运算符重载需要加上 operator<< <T> friend ostream & operator<< <T> (ostream &out, Complex &c); public: Complex(T a, T b); Complex operator+(Complex &c); void printCom(); private: T a; T b; }; // 类模板的构造函数,在类的外部 template <typename T> Complex<T>::Complex(T a, T b) { this->a = a; this->b = b; } // 模板类的函数,要把 返回的类型具体化参数化 template <typename T> Complex<T> Complex<T>::operator+(Complex<T> &c) { Complex temp(c.a + a, c.b + b); return temp; } template <typename T> void Complex<T>::printCom() { cout << "a: " << a << "\nb: " << b << endl; } //友元函数的 // 模板是两次编译的,第一次编译和第二次的生成函数头不一样, template <typename T> ostream & operator<< (ostream &out, Complex<T> &c) { out << "a: " << c.a << "\nb: " << c.b << endl; return out; } void main() { Complex<int> c1(1, 2); Complex<int> c2(3, 4); Complex<int> c3 = c1 + c2; c3.printCom(); cout << c3 << endl; system("pause"); }
4、类模板中的 static 关键字
static关键字是属于一个类的,当调用类模板时,每种参数都会调用自己的 static 关键字。
static T a;
T AA<T>::a = 0;