Şablon avantajları
Fonksiyon şablonları çeşitli veri tiplerinde benzer işlemler yapmak istediğinizde kullanılır (bir dizideki maksimum değerli elmanı bulmak gibi). Şablonların avantajı, her farklı tip için ayrı aşırı yükleme yapmanızı gerektirmemesidir. Her farklı veri tipi için aşırı yükleme yapmak yerine
double ArrayMax(double array[])
{
...
}
int ArrayMax(int array[])
{
...
}
uint ArrayMax(uint array[])
{
...
}
long ArrayMax(long array[])
{
...
}
datetime ArrayMax(datetime array[])
{
...
}
|
sadece bir şablon fonsiyonu yazmamız yeterli
template<typename T>
T ArrayMax(T array[])
{
if(ArraySize()==0)
return(0);
uint max_index=ArrayMaximum(array);
return(array[max_index]);
}
|
bunu kaynak kodunuzda kullanabilmeniz için:
double high[];
datetime time[];
....
double max_high=ArrayMax(high);
datetime lasttime=ArrayMax(time);
|
Burada, kullanılan verinin tipini belirten T biçimsel parametresi, derleme esnasında gerçekte uygulanan tip ile değiştirilir. Yani derleyici herbir tip için ( double, datetime, vb) otomatik olarak bir fonksiyon oluşturur. MQL5 dili, yaklaşımın tüm avantajları ile sınıf sablonları oluşturmanıza olanak sağlar.
Sınıf şablonları
Sınıf şablonları template anahtar sözcüğü ve açı parantezlerle <>, typename anahtar sözcüğü ile biçimsel parametreler sıralanarak bildirilir. Bu girdi, bir sınıf uygulaması yaparken, bir reel değişkeni tanımlayan T biçimsel parametresi ile bir jenerik sınıf üzerinde çalışıldığı konusunda derleyiciyi bilgilendirir. Örnek olarak T tipli elemanlardan oluşan bir diziyi depolamak için bir vektör sınıfı oluşturalım:
#define TOSTR(x) #x+" " // bir nesne ismini göstermek için makro
//+------------------------------------------------------------------+
//| T-tipi bileşenleri depolamak için bir vektör sınıfı |
//+------------------------------------------------------------------+
template <typename T>
class TArray
{
protected:
T m_array[];
public:
//--- yapıcı varsayılan olarak 10 elemanlı bir dizi oluşturur
void TArray(void){ArrayResize(m_array,10);}
//--- belirtilen dizi boyutuna göre dizi oluşturmak için bir yapıcı
void TArray(int size){ArrayResize(m_array,size);}
//--- TArray tipli nesnede depolanan verinin tipine ve miktarına dönüş yap
string Type(void){return(typename(m_array[0])+":"+(string)ArraySize(m_array));};
};
|
Şimdi çeşitli veri tipleriyle çalışmak için farklı yöntemler kullanarak üç TArray nesnesi oluşturalım
void OnStart()
{
TArray<double> double_array; // vektörün varsayılan boyutu 10
TArray<int> int_array(15); // vectör boyutu 15
TArray<string> *string_array; // TArray<string> vector için işaretçi
//--- dinamik nesne oluştur
string_array=new TArray<string>(20);
//--- nesne ismini veri tipini ve boyutunu günlükte görüntüle
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());
//--- program tamamlanmadan bir dinamik nesneyi sil
delete(string_array);
}
|
Çalıştırılan betiğin sonuçları:
double_array (double:10)
int_array (int:15)
string_array (string:20)
|
Artık, farklı veri tiplerine sahip (double, int ve string) üç vektörümüz var.
Sınıf şablonları taşıyıcıların (farklı tiplerdeki nesneleri kapsüllemek için kullanılan nesneler) geliştirilmesi için uygundur. Taşıyıcı nesneler belli tipteki diğer nesneleri içerirler. Genellikle depolanan verilerle yapılan çalışmalar hemen taşıyıcıya eklenir.
Örneğin, dizi dışındaki elemanlara erişimi kısıtlayan bir sınıf şablonu oluşturabilir ve "kapsam dışı" kritik halarını önleyebilirsiniz.
//+------------------------------------------------------------------+
//| Bir dizi elamnına serbest erişim sağlayan bir sınıf |
//+------------------------------------------------------------------+
template<typename T>
class TSafeArray
{
protected:
T m_array[];
public:
//--- varsayılan yapıcı
void TSafeArray(void){}
//--- belirtilen boyutta dizi oluştumak için yapıcı
void TSafeArray(int size){ArrayResize(m_array,size);}
//--- dizi boyutu
int Size(void){return(ArraySize(m_array));}
//--- dizi boyutunu değiştir
int Resize(int size,int reserve){return(ArrayResize(m_array,size,reserve));}
//--- diziyi boşalt
void Erase(void){ZeroMemory(m_array);}
//--- indise göre dizi elemanına erişim sağlayan operatör
T operator[](int index);
//--- dizinin tüm elemanlarını tekseferde alabilmek için atama operatörü
void operator=(const T &array[]); // T tipli dizi
};
//+------------------------------------------------------------------+
//| İndisine göre eleman alma |
//+------------------------------------------------------------------+
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, %d indisi (0-%d) kapsamında değil!",__FUNCTION__,index,max);
return(invalid_value);
}
//---
return(m_array[index]);
}
//+------------------------------------------------------------------+
//| Dizi için atama |
//+------------------------------------------------------------------+
template<typename T>
void TSafeArray::operator=(const T &array[])
{
int size=ArraySize(array);
ArrayResize(m_array,size);
//--- T tipi, kopyalama işlemini desteklemeli
for(int i=0;i<size;i++)
m_array[i]=array[i];
//---
}
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
int copied,size=15;
MqlRates rates[];
//--- fiyat dizisini kopyala
if((copied=CopyRates(_Symbol,_Period,0,size,rates))!=size)
{
PrintFormat("CopyRates(%s,%s,0,%d) çağrısı %d hata koduna dönüş yaptı",
_Symbol,EnumToString(_Period),size,GetLastError());
return;
}
//--- bir taşıyıcı oluşturup MqlRates dizisini ekle
TSafeArray<MqlRates> safe_rates;
safe_rates=rates;
//--- dizi kapsamında bir indis
int index=3;
PrintFormat("Close[%d]=%G",index,safe_rates[index].close);
//--- indis dizi kapsamı dışında
index=size;
PrintFormat("Close[%d]=%G",index,safe_rates[index].close);
}
|
Şablon bildirimlerinin sınıf bildirimleri dışında yöntem tanımlarken de kullanılabileceğini not ediniz:
template<typename T>
T TSafeArray::operator[](int index)
{
...
}
template<typename T>
void TSafeArray::operator=(const T &array[])
{
...
}
|
Sınıf ve fonksiyon şablonları, virgülle eyrılmış şekilde biçimsel parametreler kullanabilmenizi sağlar. Örneğin, "anahtar – değer" çiftlerini kaydetmek için bağıntılar:
template<typename Key, template Value>
class TMap
{
...
}
|
Ayrıca bakınız
Fonksiyon şablonları, Aşırı Yükleme