Class Templates
模板的优势
函数模板适用于需要在不同类型的数据上执行类似操作的情况,例如,在数组中查找最大元素。使用模板的主要优势是无需为每种类型单独编写重载函数。无需为每种类型声明多个重载版本
double ArrayMax(double array[])
{
...
}
int ArrayMax(int array[])
{
...
}
uint ArrayMax(uint array[])
{
...
}
long ArrayMax(long array[])
{
...
}
datetime ArrayMax(datetime array[])
{
...
}我们只需要编写一个模板函数
template<typename T>
T ArrayMax(T array[])
{
if(ArraySize()==0)
return(0);
uint max_index=ArrayMaximum(array);
return(array[max_index]);
}以便在代码中使用:
double high[];
datetime time[];
....
double max_high=ArrayMax(high);
datetime lasttime=ArrayMax(time);在这里,指定数据类型的T形式参数在编译时被替换为实际使用的类型,即编译器会自动为每个类型生成单独的函数——double、datetime等。MQL5还允许您利用该方法的全部优势来开发类模板。
类模板
类模板使用模板关键字声明,后面是尖括号<>,列出形式参数的列表,并使用typename关键字。此声明告知编译器正在处理一个通用类,其中T形式参数在实现类时定义了实际变量类型。例如,让我们创建一个用于存储T类型元素的向量的类:
#define TOSTR(x) #x+" " // macro for displaying an object name
//+------------------------------------------------------------------+
//| Vector class for storing T-type elements |
//+------------------------------------------------------------------+
template <typename T>
class TArray
{
protected:
T m_array[];
public:
//--- constructor creates an array for 10 elements by default
void TArray(void){ArrayResize(m_array,10);}
//--- constructor for creating a vector with a specified array size
void TArray(int size){ArrayResize(m_array,size);}
//--- return a type and amount of data stored in the TArray type object
string Type(void){return(typename(m_array[0])+":"+(string)ArraySize(m_array));};
};接下来,让我们应用不同的方法在程序中创建三个TArray对象,以便处理各种类型
void OnStart()
{
TArray<double> double_array; // vector has a default size of 10
TArray<int> int_array(15); // vector has a size of 15
TArray<string> *string_array; // pointer to TArray<string> vector
//--- create a dynamic object
string_array=new TArray<string>(20);
//--- display an object name, data type and vector size in the Journal
PrintFormat("%s (%s)",TOSTR(double_array),double_array.Type());
PrintFormat("%s (%s)",TOSTR(int_array),int_array.Type());
PrintFormat("%s (%s)",TOSTR(string_array),string_array.Type());
//--- remove a dynamic object before completing the program
delete(string_array);
}脚本执行结果:
double_array (double:10)
int_array (int:15)
string_array (string:20)现在,我们有3个具有不同数据类型的向量:double、int和string。
类模板非常适合开发容器——用于封装任何其他类型对象的对象。容器对象是已经包含特定类型对象的集合。通常,存储的数据操作会立即内置到容器中。
例如,您可以创建一个类模板,禁止访问数组外的元素,从而避免“超出范围”的严重错误。
//+------------------------------------------------------------------+
//| Class for a free access to an array element |
//+------------------------------------------------------------------+
template<typename T>
class TSafeArray
{
protected:
T m_array[];
public:
//--- default constructor
void TSafeArray(void){}
//--- constructor for creating the array of a specified size
void TSafeArray(int size){ArrayResize(m_array,size);}
//--- array size
int Size(void){return(ArraySize(m_array));}
//--- change the array size
int Resize(int size,int reserve){return(ArrayResize(m_array,size,reserve));}
//--- release the array
void Erase(void){ZeroMemory(m_array);}
//--- operator for accessing the array element by index
T operator[](int index);
//--- assignment operator for receiving all elements from the array at once
void operator=(const T &array[]); // T type array
};
//+------------------------------------------------------------------+
//| Receiving an element by index |
//+------------------------------------------------------------------+
template<typename T>
T TSafeArray::operator[](int index)
{
static T invalid_value;
//---
int max=ArraySize(m_array)-1;
if(index<0 || index>=ArraySize(m_array))
{
PrintFormat("%s index %d is not in range (0-%d)!",__FUNCTION__,index,max);
return(invalid_value);
}
//---
return(m_array[index]);
}
//+------------------------------------------------------------------+
//| Assigning for the array |
//+------------------------------------------------------------------+
template<typename T>
void TSafeArray::operator=(const T &array[])
{
int size=ArraySize(array);
ArrayResize(m_array,size);
//--- T type should support the copying operator
for(int i=0;i<size;i++)
m_array[i]=array[i];
//---
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
int copied,size=15;
MqlRates rates[];
//--- copy the array of quotes
if((copied=CopyRates(_Symbol,_Period,0,size,rates))!=size)
{
PrintFormat("CopyRates(%s,%s,0,%d) returned %d error code",
_Symbol,EnumToString(_Period),size,GetLastError());
return;
}
//--- create a container and insert the MqlRates value array to it
TSafeArray<MqlRates> safe_rates;
safe_rates=rates;
//--- index within the array
int index=3;
PrintFormat("Close[%d]=%G",index,safe_rates[index].close);
//--- index outside the array
index=size;
PrintFormat("Close[%d]=%G",index,safe_rates[index].close);
}请注意,在描述类声明之外的方法时也应使用模板声明:
template<typename T>
T TSafeArray::operator[](int index)
{
...
}
template<typename T>
void TSafeArray::operator=(const T &array[])
{
...
}类模板和函数模板允许定义多个逗号分隔的形式参数,例如,用于存储“键-值”对的Map集合:
template<typename Key, template Value>
class TMap
{
...
}另请参阅
最后更新于