1.模板(template)是C++支持参数化多态性的工具,是C++语言中常用的一种高级泛型编程技术。
2.模板是在函数和类的基础上提供了更高一层的抽象,在不确定要操作数据的类型的情况下就实现操作方法。
3.
4.函数模板的原型:
template <类型参数表 typename(class) T1,typename T2>
<返回类型> <函数名>(<函数形参表>)
{
<函数体>
}
5.调用函数模板的表达式同调用一般函数的表达式格式相同,由函数名和实参表所组成,函数模板中的每个类型参数将在调用时被赋予与该类型的形参所对应的实参的类型。
6.当调用一个函数模板时,系统首先确定类型参数所对应的具体类型,并按该类型生成一个具体函数,然后再调用这个具有确定类型的具体函数。
7.函数模板的显示特化举例如下:
typedef const char *PCC;
template<> PCC max< PCC >( PCC s1, PCC s2 )
{
return ( strcmp( s1, s2 ) > 0 ? s1 : s2 );
}
8.显示特化相当于一个特使处理,也可以对函数模板进行重载,处理特殊的情况。
9.函数模板可以被重载,例如,下面给出函数模板min()的两个有效的重载声明。
template<typename type>type min(type t1,type t2)
{
return t1<t2?t1:t2;
}
template<typename type>type min(type t1,float ival)
{
return t1<ival?t1:ival;
}
10.函数模板重载时要注意二义性问题,解决办法是显示指定模板实参。
11.函数模板可以被重载,而且函数模板可以与一个普通非模板函数同名。
12.到底调用哪个函数取决于这些函数中的哪一个与函数实参类型匹配得最好。
13.当如果都差不多符合时,会优先调用普通函数,因为调用模板还必须实例化函数,所以不会调用模板。
14.代码如下:
#include "Utility.h"
/*函数模板特点:
1、通过对功能相似的函数进行抽象
2、函数模板可以实例化出若干个模板函数
3、函数模板同样可以构成“函数模板的重载”,
靠参数的个数、类型不同来实现
4、函数模板 与 普通函数能构成重载,优先调用普通函数
格式:
template<typename T>返回值类型 函数名(参数表)
{
函数体
}
*/
//函数模板的功能:同类型数据求和
template<typename T>T getSum(T _a , T _b)
{
return _a+_b;
}
template<typename T1, typename T2>T1 getSum(T1 a ,T2 b)
{
return a+b;
}
double getSum(double a , double b)
{
return a+b;
}
//------------函数模板的重载------------
//函数模板的隐式特化
template<typename T>T _Max(T a , T b)
{
return a>b?a:b;
}
//显式特化
typedef const char * PCC;
template<> PCC _Max<PCC>(PCC p1,PCC p2)
{
return ((strcmp(p1,p2)>0)?p1:p2);
}
template<typename T>T _Min(T a , T b )
{
return a<b?a:b;
}
double _Min(double a , int b)
{
return a<b?a:b;
}
class CMonster
{
public:
CMonster(){};
~CMonster(){};
};
class CPlayer{};
void main()
{
//函数模板的调用原理:
// 当系统检测到调用了一个函数模板之后,它会检测函数
//参数是否相同,如果相同,根据实参类型,通过函数模
//板实例化出相应的模板函数
cout<<getSum(3,5)<<endl; //调用int 型模板函数
cout<<getSum(3.2,5.75)<<endl; //调用double型模板函数
cout<<getSum(1.3f,5.5f)<<endl; //调用float 型模板函数
cout<<getSum('(',')')<<endl; //调用char 型模板函数
cout<<getSum('A',32)<<endl;
cout<<_Max(5,10)<<endl;
cout<<_Max("ABC","abc")<<endl;
cout<<_Min(12.0,10)<<endl; //普通函数
cout<<_Min(12.0,10.0)<<endl;//函数模板
cout<<_Min(12,10.0)<<endl; //
CMonster * pMonster = new CMonster();
//使用。。。。。。
Safe_Delete(pMonster);
CPlayer * pPlayer = new CPlayer();
//使用。。。。。。
Safe_Delete(pPlayer);
int * pValue = new int(100);
//使用。。。。。。
Safe_Delete(pValue);
//new了一个int数组
int * pArray = new int[5];
for( int i = 0 ; i < 5 ; ++i )
pArray[i] = i;
for( int i = 0 ; i < 5 ; ++i )
cout<<"pArray["<<i<<"] = "<<pArray[i]<<endl;
Safe_Delete_Array(pArray);
system("pause");
}
15.类模板的定义:
template <类型参数表>
class 类模板名
{
<类体>
};
16.类模板的使用就是将类模板实例化为一个个具体的类,即模板类,然后再通过模板类建立对象。
<类模板名> <类型参数表> 对象1, … ,对象n;
17.<类模板名> <类型参数表>在一起变为模板类名字。
18.模板参数列表包含了两种参数:类型参数和非类型参数。
19.模板参数并不局限于类型,普通值也可以作为模板参数。
20.类模板也允许有静态成员。对于一个类模板的每一个实例化类,其所有的对象共享其静态成员。
21.类模板的静态成员在模板定义时是不会被创建的,其创建是在类的实例化之后。
22.静态成员是类模板实例化类的静态成员,而不属于类模板。
23.类模板的继承:
1)一般类(其中不使用类型参数的类)作基类,派生出类模板(其中要使用类型参数)。
class CB
{
……
};
template < typename T> class CA:public CB
{
T t; //私有数据为T 类型的
public:
……
};
2)类模板作基类,派生出新的类模板。但仅基类中用到类型参数T(而派生的类模板中不使用T)
template < typename T>
class CB
{
T t;
public:
T gett()
{
return t;
}
……
};
template <typename T>
class CA:public CB<T>
{
//CA为类模板,其基类CB也为类模板。
//类型参数T将被“传递”给基类CB,//本派生类中并不使用该类型参数T
double t1;
public:
……
};
3)类模板作基类,派生出新的类模板,且基类与派生类中均使用同一个类型参数T。
template < typename T> class CB
{
T t;
public:
T gett()
{
return t;
}
……
};
template <class T>
class CA:public CB<T>
{
//CA为类模板,其基类CB也为类模板。
//类型参数T 将被“传递”给基类CB;//本派生类中也将使用这同一个类型
//参数T
T t1;
public:
……
};
4)类模板作基类,派生出新的类模板,但基类中使用类型参数T2,而派生类中使用另一个类型参数T1
template < typename T2> class CB
{
T2 t2;
public:
……
};
template < typename T1, typename T2>
class CA:public CB<T2>
{
//CA为类模板,其基类CB也为类模板。
//类型参数T2将被“传递”给基类CB;
//本派生类中还将使用另一个类型参
//数T1
T1 t1; //数据为T1类型的
public:
……
};
24.哪个类继承了单例类模板,哪个类就变成可单例类。
24.代码如下:
//#include "Utility.h"
//
///*
//类模板de格式:
//template<typename T> class 类名
//{};
//*/
实现数据的四则运算
//template <typename T> class COperation
//{
//protected:
//T m_Value1;//参与运算的数据1
//T m_Value2;// 2
//public:
//COperation(){};
//~COperation(){};
//void onInit(T value1 , T value2)
//{ m_Value1 = value1 ; m_Value2 = value2;};
//
//T getSum();//加法
//T getSub();//减法
//T getMul();//乘法
//T getDiv();//除法
//};
类模板中的函数成员在对应的cpp文件中的实现格式:
template<typename T> 返回值类型 模板类名::函数名(参数表)
{}
//template <typename T> T COperation<T>::getSum()
//{
//return m_Value1 + m_Value2;
//}
//template<typename T>T COperation<T>::getSub()
//{
//return m_Value1 - m_Value2;
//}
//template<typename T> T COperation<T>::getMul()
//{
//return m_Value1 * m_Value2;
//}
//template<typename T> T COperation<T>::getDiv()
//{
////断言函数:当参数表达式为"假"时,程序直接中断,并
////显示错误位置。
//assert(m_Value2);
//return m_Value1/m_Value2;
//}
-----模拟数组功能的类模板-----
//template<typename T,int c_iSize> class CArray
//{
//protected:
//int m_iMaxSize;//能存储的最大元素个数
//int m_iNumElements;//当前元素个数
//public:
//T objArray[c_iSize];//数组
//public:
//CArray():m_iMaxSize(c_iSize)
//{
//m_iNumElements = 0;
//}
//void AddElement(T value);
//};
//
//template<typename T,int c_iSize>
//void CArray<T,c_iSize>::AddElement(T value)
//{
////首先判定能否向数组添加数据
//if(m_iNumElements == m_iMaxSize)
//{
//cout<<"Full......"<<endl;
//return;
//}
//
////可以添加数据
//objArray[m_iNumElements++] = value;
////m_iNumElements+=1;
//}
//void main()
//{
////类模板的使用方式:先构建模板类,再生成对象
//cout<<"----int型模板类----"<<endl;
//COperation<int> iOperation;
//iOperation.onInit(6,2);
//cout<<iOperation.getSum()<<endl;
//cout<<iOperation.getSub()<<endl;
//cout<<iOperation.getMul()<<endl;
//cout<<iOperation.getDiv()<<endl;
//
//cout<<"----float型模板类----"<<endl;
//COperation<float> fOperation;
//fOperation.onInit(6.2f,0.8f);
//cout<<fOperation.getSum()<<endl;
//cout<<fOperation.getSub()<<endl;
//cout<<fOperation.getMul()<<endl;
//cout<<fOperation.getDiv()<<endl;
//
////利用类模板创建模拟数组功能的类对象
//cout<<"----利用类模板创建模拟数组功能的类对象----"<<endl;
//CArray<int,10> intArray;
//
//for(int i = 0 ; i < 10 ; ++i)
//intArray.objArray[i] = i+1;
//
//for(int i = 0 ; i < 10 ; ++i)
//cout<<intArray.objArray[i]<<endl;
//
//cout<<"-----char Array-----"<<endl;
//CArray<char,10> charArray;
//
//for(int i = 0 ; i < 10 ; ++i)
//charArray.objArray[i] = i+65;
//
//for(int i = 0 ; i < 10 ; ++i)
//cout<<charArray.objArray[i]<<endl;
//
//cout<<"-----float Array-----"<<endl;
//CArray<float,3> floatArray;
//floatArray.AddElement(1.2f);
//floatArray.AddElement(2.2f);
//floatArray.AddElement(3.2f);
//
//floatArray.AddElement(5.2f);
//
//
//for(int i = 0 ; i < 3 ; ++i)
//cout<<floatArray.objArray[i]<<endl;
//
//
//system("pause");
//}
//--------------单例(单件)模式----------------
#include "Utility.h"
#include "Player.h"
#include "test.h"
#include "Utility.h"
#include "Player.h"
CPlayer * CPlayer::m_pPlayer = NULL;
CPlayer & CPlayer::getInstance()
{
if(m_pPlayer == NULL)
m_pPlayer = new CPlayer();
assert(m_pPlayer);
return (*m_pPlayer);
}
CPlayer * CPlayer::getInstancePtr()
{
if(m_pPlayer == NULL)
m_pPlayer = new CPlayer();
assert(m_pPlayer);
return m_pPlayer;
}
void main()
{
cout<<"x = "<<CPlayer::getInstance().getPlayerX()<<endl;
cout<<"y = "<<CPlayer::getInstance().getPlayerY()<<endl;
Test();
cout<<"x = "<<CPlayer::getInstance().getPlayerX()<<endl;
cout<<"y = "<<CPlayer::getInstancePtr()->getPlayerY()<<endl;
system("pause");
}
25.单例类模板的格式如下:
//单例模式类模板
#ifndef _Singleton_H_
#define _Singleton_H_
#include <assert.h>
template<typename T> class CSingleton
{
public:
static T* ms_Singleton;
public:
CSingleton( void )
{
assert( !ms_Singleton );
ms_Singleton = static_cast<T*>(this);
}
~CSingleton( void )
{
assert( ms_Singleton );
ms_Singleton = NULL;
}
static T& GetSingleton( void )
{
if(ms_Singleton == NULL)
ms_Singleton = new T();
assert( ms_Singleton );
return ( *ms_Singleton );
}
static T* GetSingletonPtr( void )
{
if(ms_Singleton!=NULL)
return ms_Singleton;
ms_Singleton = new T();
assert(ms_Singleton!=NULL);
return ms_Singleton;
}
};
template<typename T> T* CSingleton<T>::ms_Singleton = NULL;
#endif
26.构建单例类的四个步骤:
1)声明一个静态指向自身变量的指针
2)在类外给指针赋初始值
3)声明两个静态函数分别得到对象的引用,和指向对象的指针;
4)记得最后delete new出来的对象。