网站底部版权html代码,wordpress文章发布函数,织梦网站做站群,企业快速建站都有哪些技巧呢参考视频#xff1a;C类模板_哔哩哔哩_bilibili
遗留问题#xff1a;编译器怎么处理函数模板和类模板
目录
一、为什么会有函数模版#xff1f;函数模板是为了解决什么问题#xff1f;
二、函数模板的概念
三、函数模版的使用
四、函数模板的特化
五、类模板的概念 …参考视频C类模板_哔哩哔哩_bilibili
遗留问题编译器怎么处理函数模板和类模板
目录
一、为什么会有函数模版函数模板是为了解决什么问题
二、函数模板的概念
三、函数模版的使用
四、函数模板的特化
五、类模板的概念
六、类模板的使用
七、类模板的特化
八、类模板的偏特化 一、为什么会有函数模版函数模板是为了解决什么问题 函数模板是为了减少重复代码是整合多个函数的函数体相同而区别只在参数类型不同的代码冗余的情况。不用函数模板前多个函数的参数类型不同但函数体相同导致重复代码较多。有了函数模板只需要一份函数体一份代码就可以实现原来需要几个函数体才实现的功能例如不使用函数模板时要分别对int、char等类型的两个数据做是否相等判断需要定义多个函数
bool isEqual( int nA, int nB)
{return nA nB;
}bool isEqual(char cA, char cB)
{return cA cB;
}int main()
{int nA 10;int nB 20;char cA A;char cB B;std::cout isEqual(nA, nB) std::endl;std::cout isEqual(cA, cB) std::endl;return 0;
}可见重载的两个函数的函数体实现一样函数体代码重复下面是使用函数模板的代码
#include iostream
//使用模板代替原来的多个函数
templatetypename T
bool isEqual(T tA, T tB)
{return tA tB;
}int main()
{
//变量以匈牙利命名法命名int nA 10;int nB 20;char cA A;char cB B;
//编译期间编译器根据实参类型和模板函数生成函数bool isEqual(int, int);std::cout isEqual(nA, nB) std::endl;
//编译期间编译器根据实参类型和模板函数生成函数bool isEqual(char, char);std::cout isEqual(cA, cB) std::endl;return 0;
}二、函数模板的概念 函数模板是用于生成函数的模板。在编译阶段编译器会根据函数模板的使用情况(例如上面的isEqual(nA, nB)、isEqual(cA, cB)创建出函数名相同参数类型由编译器判断的若干函数。通过函数模板创建的函数拥有相同的函数体只是函数的参数类型不同。
三、函数模版的使用 每当在一个编译单元经过预处理的.cpp文件中使用了函数模版则必须在该编译单元中给出函数模版的定义要是把函数模板声明写在.h文件函数模板声明写在.cpp文件然后在使用函数模板时只使用include 包含函数模板的头文件不给出函数模板的定义那么编译会报无法解析的外部符号错误)。因此为了避免在每个编译单元都定义函数模板建议在头文件中对函数模板进行声明定义即将函数模板的声明和定义都写在一个头文件中然后在需要使用函数模板的地方加上该头文件。 函数模版的声明
templatetypename T返回类型 函数名(参数列表)其中T表示任意类型参数的类型和返回类型都可以指定为T
函数模版的定义
templatetypename T,.. //可指定多个泛型
返回类型 函数名(参数列表)
{//函数体
}
将一、为什么会有函数模版函数模板是为了解决什么问题这一节中的函数模板的声明和定义写在isEqualFunc.h头文件中再使用
#ifndef ISEQUALFUNC_H
#define ISEQUALFUNC_H
//函数模板声明
templatetypename T
bool isEqual(T tA, T tB);//函数模板定义
templatetypename T
bool isEqual(T tA, T tB)
{return tA tB;
}#endif // ISEQUALFUNC_H
//这是main.cpp
#include isEqualFunc.h
#include iostreamint main()
{//变量以匈牙利命名法命名int nA 100111111;int nB 111111;char cA A;char cB A;//编译期间编译器根据实参类型和模板函数生成函数bool isEqual(int, int);std::cout isEqual(nA, nB) std::endl;//编译期间编译器根据实参类型和模板函数生成函数bool isEqual(char, char);std::cout isEqual(cA, cB) std::endl;return 0;
}四、函数模板的特化
函数模板特化是指在实例化函数模板时对特定类型的实参进行特殊的处理即当实参为特定类型时通过函数模板生成的函数会有不同的函数体。
特化时需要为函数模板添加新的定义方式如下
template
返回类型 函数名特定的参数类型(参数列表)
{//函数体
}
在上面的例子中对于char*类型的字符串使用上面的函数模板无法对字符串正确判断是否相等因为字符串比较不是直接比较指针是否相等而要调用strcmp函数判断对上面的例子就需要对函数模板进行特化
#ifndef ISEQUALFUNC_H
#define ISEQUALFUNC_H
#include string.h
//函数模板声明
templatetypename T
bool isEqual(T tA, T tB);//函数模板定义
templatetypename T
bool isEqual(T tA, T tB)
{return tA tB;
}//函数模板的特化
template
bool isEqual char* ( char* szA, char* szB)
{return strcmp(szA, szB) 0;
}#endif // ISEQUALFUNC_H
//这是main.cpp
#include isEqualFunc.h
#include iostreamint main()
{//变量以匈牙利命名法命名int nA 100111111;int nB 111111;char cA A;char cB A;char szA[4] AAA;char szB[4] AAA;// 编译器会怎么处理函数模板和特化待参考https://blog.csdn.net/zgaoq/article/details/85232968//编译期间编译器根据实参类型和模板函数生成函数bool isEqual(int, int);std::cout isEqual(nA, nB) std::endl;//编译期间编译器根据实参类型和模板函数生成函数bool isEqual(char, char);std::cout isEqual(cA, cB) std::endl;std::cout isEqual(szA, szB) std::endl; //判断字符串是否相等return 0;
}五、类模板的概念
类模板是用于生成类的模板。在编译阶段编译器会根据类模板的使用情况创建出仅部分成员数据类型和部分成员函数的参数类型不同其他完全相同的若干类。
通过类模板的这些特性我们可以尝试写出用于存放不同类型数据的容器。
六、类模板的使用
类模板的声明格式
templatetypename T,...
class 类名
{//成员
};
类模板的成员函数定义如下,一般类模板的定义也应该写在头文件中
templatetypename T,...
返回类型 类名T,...::成员函数名(形参列表)
{//函数体
}
下面是一个例子这个例子定义了一个MyArray的类模板其中数据成员是数组通过泛型T达到可定义各种类型数组的目的而所有对这个数组的操作函数都相同这样就不用针对不同类型的数组定义不同的类达到了复用代码即减少重复代码的目的
//这是myArray.h
#ifndef MYARRAY_H
#define MYARRAY_H
#include iostream
constexpr int m_nMaxLen 20;template typename T
class MyArray
{
public:MyArray():size(0){}//添加数据bool addData(T value);//删除数据bool deleteData(T value);//获取数据T getData(int nIndex);void print(){for(int i 0; i size; i){std::cout data[i] std::endl;}}
private:T data[m_nMaxLen];int size;
};templatetypename T
bool MyArrayT::addData(T value)
{if(size m_nMaxLen){return false;}data[size] value;size;return true;
}templatetypename T
bool MyArrayT::deleteData(T value)
{if(size 0){return false;}int nDataIndex -1;for(int i 0; i size; i){if(data[i] value){nDataIndex i;break;}}if(nDataIndex -1){std::cout 找不到该数据 std::endl;return false;}else{for(int i nDataIndex; i size -1; i){data[i] data[i1]; //往前移动后面的数据即可以删除该数据}size --;}return true;
}templatetypename T
T MyArrayT::getData(int nIndex)
{if(nIndex 0 nIndex size){return data[nIndex];}else{return (T)0;}
}#endif // MYARRAY_H//这是main.cpp
#include myarray.h
#include iostream
int main()
{std::cout ----int begin---- std::endl;MyArrayint intData;for(int i 1; i 10; i){intData.addData(i);}intData.print();std::cout -------- std::endl;intData.deleteData(11);std::cout -------- std::endl;intData.print();std::cout intData.getData(0) std::endl;std::cout ----int end---- std::endl;std::cout ----char begin---- std::endl;MyArraychar charData;for(int i 1; i 10; i){charData.addData(A i);}charData.print();std::cout -------- std::endl;charData.deleteData(B);std::cout -------- std::endl;charData.print();std::cout charData.getData(1) std::endl;std::cout ----char end---- std::endl;return 0;
}七、类模板的特化
类模板的特化是在实例化类模板时对特定类型的泛型进行特殊的处理即用户指定所有特定类型的类模板时通过特化类模板生成的类可能与其他类有完全不同的结构。
特化类模板是需要对整个类模板进行声明定义
template
class 类名指定类型,指定类型,...
{
//类成员
};
这里对第六节中的例子添加特化
#ifndef MYARRAY_H
#define MYARRAY_H//....其他代码不变//对特定泛型的类的成员函数进行特化
template
MyArraychar::MyArray()
{std::cout MyArraychar::MyArray() std::endl;
}//对特定泛型的类进行特化
//这里例子可能不太恰当只是展示如何对特定类型的类进行特化
template
class MyArrayfloat
{public:MyArray();private:float data;
};MyArrayfloat::MyArray()
{std::cout MyArrayfloat::MyArray() std::endl;
}#endif // MYARRAY_H
八、类模板的偏特化
偏特化和特化类似只是特化会指定所有的泛型而偏特化只指定部分泛型。
偏特化类模板需要对整个类模板进行声明定义
template typename T,...不需特化的泛型...
class 类名指定类型,...不需特化的泛型名,...
{//类成员;
}
例子
#ifndef PAIR_H
#define PAIR_H
#include iostream
templatetypename T1, typename T2
class Pair
{
public:Pair();
private:T1 m_first;T2 m_second;
};templatetypename T1, typename T2
PairT1, T2::Pair()
{std::cout PairT1, T2::Pair() std::endl;
}//偏特化
templatetypename T2
class Pairchar, T2
{
public:Pair();
private:char first;T2 second;
};templatetypename T2
Pairchar, T2::Pair()
{std::cout Pairchar, T2::Pair() std::endl;
}#endif // PAIR_H//这是main.cpp
#include iostream
#include Pair.h
int main()
{Pairint, int pNn;Pairchar, int pCn;return 0;
}
运行结果