介绍: 模板是c++泛型思想的主要体现。即一份代码多种实现(形态)。将类型参数化提高代码复用性。 多态,带参宏,函数重载,模板(类和函数)
注意: 模板的特性要求在声明的上下文中必须能找到它的实现。 所以,模板函数或类的声明定义方式: 1.不进行文件分离编译处理,总是放在同一个文件中。 2.使用export关键词,不建议使用,而且后面的c++标准中,好像已经放弃使用了… 3、使用#include指令将模板实现文件(.c/.cpp)导入到声明文件(.h)中,从而实现分离编译,示例详见下文模板类介绍。模板类主要用于类模板。
拓展: 1、头文件不能含有有内存的东西,否则会出现多处定义,出现二义性,导致报错 2、.h文件是不直接参与编译的,#include指令包含的.h文件只会进行预编译,不会进行编译,也就是说不会进行语法检查(此处主要不检查是否出现二义性)
定义方式:
template<class T> T fun(T a, T b) { T result=a+b; return result; } //使用 //main.cpp fun(1,2);//隐式推导类型,不推荐使用 fun<int>(12,23);//显示指定类型,个人爱好,推荐使用隐式类型推导 函数模板的调用优先级顺序: 类型完全匹配的普通函数>类型完全匹配的模板函数>可以隐式转换匹配的模板函数 ELSE 报错
class和typename等效。
函数模板重载: 通过模板参数列表或者函数参数列表不同构成函数重载。模板参数列表里面也可以有具体化类型参数,比如:template<class T,class T1,int a=90>这是合法的,其中也可以给定参数缺省值,满足参数缺省规则即可
定义使用示例: 1、不使用分离编译,即在同一文件下进行声明和定义
template<class T> class MyClass { public: void fun(T a) { cout << "类中定义" << endl; } };类外定义:
template<class T> class MyClass { public: void fun(T a); }; template<class T> void MyClass<T>::fun(T a) { cout<<"类外定义"<<endl; }模板类使用:
MyClass<int> obj1; obj1.fun();2、使用分离编译:
示例代码如下
//Obj.h #ifndef _OBJ_H//防止多次包含,这里不这样做就死循环了 #define _OBJ_H #include<iostream> using namespace std; template<class T,class T2> class Obj { public: void fun(); }; #include "Obj.cpp"//因为#include指令只是在预编译阶段进行*展开*处理, //所以需要将.cpp中的内容放在声明的后面,否则不认识 #endif //Obj.cpp #ifndef _OBJ_CPP #define _OBJ_CPP #include "Obj.h" template<class N, class M> void Obj<N, M>::fun() { cout << "yes" << endl; } #endif // !_OBJ_CPP //main.cpp Obj<int, string> c; c.fun();共同点 两者放于文件首,都是用于防止一份文件多次包含。 区别:
#ifnde、#define、#endif…是c++语法支持的,支持性更好,可以防止一份文件或同内容的文件多次包含。兼容性好,推荐使用。但是要预防宏定义名字相同
#pragma once 是编译器支持,有的编译器可能不支持。作用也在于防止文件多次包含。优点在于不需要为取名字而烦恼…