介绍: 模板是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();
拓展:#pragma once 和#ifnde…的区别
共同点
两者放于文件首,都是用于防止一份文件多次包含。
区别:
#ifnde、#define、#endif…是c++语法支持的,支持性更好,可以防止一份文件或同内容的文件多次包含。兼容性好,推荐使用。但是要预防宏定义名字相同
#pragma once 是编译器支持,有的编译器可能不支持。作用也在于防止文件多次包含。优点在于不需要为取名字而烦恼…