C++模板
一,函数模板
1,函数模板语法规则
template<typename T>或template<class T>
template:告诉编译器开始泛型编程
typename:告诉编译器T是一个泛指类型
2,函数调用
自动类型推导调用 :根据参数的类型推导
具体类型显示调用:函数名<T的具体类型>(实参1,实参2)
3,函数模板深入理解
- 编译器并不是把函数模板处理成能够处理任意类型的函数
- 编译器从函数模板通过具体类型产生不同的函数
- 编译器会对函数模板进行两次编译
-
- 在声明的地方对模板代码本身进行编译
- 在调用的地方对参数替换后的代码进行编译
4,函数模板与重载
函数模板可以像普通函数一样可以重载
函数模板不允许自动类型转换,普通函数可以
三条匹配规则:
- C++编译器优先考虑普通函数
- 如果函数模板可以产生一个更好的匹配,那么选择模板
- 如果普通函数和模板都可以调用,但是普通函数参数类型要自动转换
- 可以通过空模板实参列表的语法限定编译器只通过模板匹配
- 函数名<>(参数1,参数2)
5,多参数函数模板
当声明的类型参数为返回值类型时无法进行自动类型推导。
不完美的解决办法:返回参数的类型申明到第一个位置,调用时只需显示声明返回参数类型即可
例子:
int Max(int a, int b)
{
cout<<"int Max(int a, int b)"<<endl;
return a > b ? a : b;
}
template<typename T>
T Max(T a, T b)
{
cout<<"T Max(T a, T b)"<<endl;
return a > b ? a : b;
}
template<typename T>
T Max(T a, T b, T c)
{
cout<<"T Max(T a, T b, T c)"<<endl;
return Max(Max(a, b), c);
}
cout<<Max(a, b)<<endl;//优先考虑普通函数
cout<<Max<>(a, b)<<endl;//空模板实参列表,所以调用函数模板
cout<<Max(3.0, 4.0)<<endl;//因为是float型,不可能调用那个int的函数,而是函数模板。可以产生更好的匹配
cout<<Max(5.0, 6.0, 7.0)<<endl;//函数模板
cout<<Max('a', 100)<<endl;//那个普通函数,因为函数模板不能自动类型转换
二,类模板
1,template<typename T>也可以用类上,称为类模板,和函数模板用法类似
2,声明的泛指类型 T 可用于声明成员变量和成员函数
3,类模板只能利用具体类型定义对象,不能自动类型推导。
4,类模板在工程上的使用
由于类模板的编译机制不同 所以不能像普通类样分开实现后在使用时只包含头文件 。一般是在一个叫.hpp的头文件实现。
格式:
#ifndef _ARRAY_DEF_H_
#define _ARRAY_DEF_H_
#endif
在模板类外实现成员函数时,需要加上template<typename T>
5,类模板可以被特化
使用template<>申明一个类时,表示这是一个特化类。
template<>
class test<int>//test类的int特化
特化类模板意义:
当类模板在处理某种特定类型有缺陷时 ,可以通过类模板的特化来克服处理这种特定类型带来的不足 。优先匹配特化
6,类模板可以定义多个类型参数
类模板可以被局部特化
可以指定类模板的特定实现,并要求某些类型参数仍然必须得模板的用户指定
7,为什么需要特化 而不重新定义新类?
- 特化和重新定义新类看上去本质没什么区别,如果定义了一个新类,就有一个模板类和新类,在使用时就会考虑是使用新类还是模板类。
- 如果使用特化类,编译器优先使用特化类。
8,函数模板和类模板的模板参数可以是普通数值
template<typename T,int N>
非类型模板参数的限制:
- 变量不能作为模板参数
- 浮点数和类对象不能作为模板参数
- 全局指针不能作为模板参数
三,工程问题
对于堆内存来说
1,内存越界常发生在数组
解决方法:数组类
2,内存泄漏和内存多次释放常发生于指针的使用过程中
解决方法:智能指针
工程中的智能指针是一个类模板
- 通过构造函数接管申请的堆内存
- 通过析构函数确保堆内存被及时释放
- 通过重载指针运算符 * --> 模拟指针的行为
- 通过重载比较运算符 == 和!= 模拟指针的比较
数组类:
array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_
template<typename T>
class Array
{
private:
int mLength;
T* mSpace;
public:
Array(int length);
Array(const Array& obj);
int length();
~Array();
T& operator [](int i);
Array& operator =(const Array& obj);
bool operator ==(const Array& obj);
bool operator !=(const Array& obj);
};
#endif
array.hpp
#ifndef _ARRAY_DEF_H_
#define _ARRAY_DEF_H_
#include <iostream>
#include "array.h"
using namespace std;
template<typename T>
Array<T>::Array(int length)
{
if(length<0){
mLength=0;
}
mLength=length;
mSpace=new T[mLength];
}
template<typename T>
Array<T>::Array(const Array& obj)
{
mLength=obj.mLength;
mSpace=new T [mLength];
for(int i=0;i<mLength;i++){
mSpace[i]=obj.mSpace[i];
}
}
template<typename T>
int Array<T>::length()
{
return mLength;
}
template<typename T>
Array<T>::~Array()
{
mLength=-1;
delete[] mSpace;
}
template<typename T>
T& Array<T>::operator [](int i)//引用可以作为左值 mSpace[i]=i,这样的形式允许
{
if(i>=mLength) {
cout<<"数组越界"<<endl;
}
return mSpace[i];
}
template<typename T>
Array<T>& Array<T>::operator =(const Array& obj)//引用的目的是,为了连续赋值 a=b=c
{
delete[] mSpace;
mLength=obj.mLength;
mSpace=new T[mLength];
for(int i=0;i<mLength;i++){
mSpace[i]=obj.mSpace[i];
}
return *this;
}
template<typename T>
bool Array<T>::operator ==(const Array& obj)
{
bool ret=true;
if(mLength==obj.mLength){
for(int i=0;i<mLength;i++){
if(mSpace[i]!=obj.mSpace[i]){
ret=false;
break;
}
}
}
else{
ret=false;
}
return ret;
}
template<typename T>
bool Array<T>::operator !=(const Array& obj)
{
bool ret=true;
return !(*this==obj);
}
#endif
//测试
int main(int argc, char *argv[])
{
Array<int> ai(5);
for(int i=0; i<ai.length(); i++)
{
ai[i] = i + 1;
}
for(int i=0; i<ai.length(); i++)
{
cout<<ai[i]<<endl;
}
Array<double> ad(10);
for(int i=0; i<ad.length(); i++)
{
ad[i] = (i + 1) / 100.0;
}
for(int i=0; i<ad.length(); i++)
{
cout<<ad[i]<<endl;
}
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
智能指针
SmartPointer.h
#ifndef _SMARTPOINTER_H_
#define _SMARTPOINTER_H_
template<typename T>
class SmartPointer
{
protected:
T* m_pointer;
public:
SmartPointer();
SmartPointer(const T* pointer);
~SmartPointer();
T* operator ->();
T& operator *();
};
#endif
SmartPointer.hpp
#ifndef _SMARTPOINTER_DEF_H_
#define _SMARTPOINTER_DEF_H_
#include "smartpointer.h"
template<typename T>
SmartPointer<T>::SmartPointer()
{
m_pointer=NULL;
}
template<typename T>
SmartPointer<T>::SmartPointer(const T* pointer)
{
m_pointer=const_cast<T*>(pointer);
}
template<typename T>
SmartPointer<T>::~SmartPointer()
{
delete m_pointer;
}
template<typename T>
T* SmartPointer<T>::operator ->()
{
return m_pointer;
}
template<typename T>
T& SmartPointer<T>::operator *()
{
return *m_pointer;
}
#endif
//测试
class Test
{
public:
int i;
void print()
{
cout<<i<<endl;
}
};
int main(int argc, char *argv[])
{
SmartPointer<int> pi = new int(5);
SmartPointer<Test> pt = new Test();
cout<<*pi<<endl;
*pi = 10;
cout<<*pi<<endl;
pt->i = 20;
pt->print();
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
上一篇: php验证显示内容
下一篇: c++ 模板 (template)