English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Nesne işaretleyicilerini MQL5'te Kullanma

Nesne işaretleyicilerini MQL5'te Kullanma

MetaTrader 5Örnekler | 9 Aralık 2021, 10:27
63 0
MetaQuotes
MetaQuotes

Giriş

MQL5'te, kodunuzda sınıf türü değişkenlerin daha fazla kullanımı için kendi sınıfınızı oluşturabilirsiniz. MQL5'te MQL5’te Nesne Oluşturma ve Silme Düzeni makalesinden zaten bildiğimiz gibi, yapılar ve sınıflar iki şekilde oluşturulabilir - otomatik ve dinamik olarak.

Otomatik olarak bir nesne oluşturmak için bir sınıf türü değişkeni bildirmeniz yeterlidir - sistem bunu otomatik olarak oluşturacak ve başlatacaktır. Dinamik olarak bir nesne oluşturmak için yeni operatörünü nesne işaretçisine açıkça uygulamak gerekir.

Ancak, otomatik ve dinamik olarak oluşturulan nesneler ile nesne işaretçisini zorunlu olarak kullanmamız gerektiğinde ve nesneleri otomatik olarak oluşturmak yeterli olduğu zaman arasındaki fark nedir? Bu konu bu makalenin konusudur. İlk olarak, nesnelerle çalışırken bazı olası tehlikeleri tartışalım ve bunları düzeltmenin yollarını düşünelim.

Geçersiz İşaretçiye Erişimde Kritik Bir Hata

Nesne işaretçilerini kullanırken hatırlamanız gereken ilk şey, kullanımdan önce nesnenin zorunlu olarak başlatılmasıdır. Geçersiz işaretçiye eriştiğinizde, MQL programının çalışması bir kritik hata ile sona erer ve program kaldırılır. Örnek olarak, CHello sınıfına sahip basit bir Uzman Danışmanı (EA) ele alalım. Sınıf örneğinin işaretçisi global seviyede bildirilir.

//+------------------------------------------------------------------+
//|                                             GetCriticalError.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| A simple class                                                   |
//+------------------------------------------------------------------+
class CHello
  {
private:
   string            m_message;
public:
                     CHello(){m_message="Starting...";}
   string            GetMessage(){return(m_message);}
  };
//---
CHello *pstatus;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- calling a method to show status
   Print(pstatus.GetMessage());
//--- printing a message if Expert Advisor has been initialized successfully
   Print(__FUNCTION__," The OnInit() function is completed");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+

pstatus değişkeni nesne işaretçisidir, ancak kasıtlı olarak yeni operatörünü kullanarak nesnenin kendisini oluşturmayı "unuttuk". Bu Uzman Danışmanı (EA) EURUSD grafiğinde başlatmaya çalışırsanız, doğal sonucu göreceksiniz - Uzman Danışman (EA), OnInit() fonksiyonunun yürütülmesi aşamasında hemen kaldırılmıştır. Uzmanlar Günlüğünde görünen mesajlar şunlardır:

14:46:17 Uzman GetCriticalError (EURUSD, H1) başarıyla yüklendi
14:46:18 GetCriticalError (EURUSD, H1) başlatılamadı
14:46:18 Uzman GetCriticalError (EURUSD, H1) kaldırıldı

Bu örnek çok basittir, hata yakalama kolaydır. Ancak, MQL5 programınız yüzlerce hatta binlerce kod satırı içeriyorsa, bu hataların yakalanması oldukça karmaşık olabilir. Özellikle acil durumlarda program davranışında öngörülemeyen faktörlere, örneğin, belirli piyasa yapısına bağlıdır.

Kullanımdan Önce İşaretçinin Kontrolü

Kritik program sonlandırmasından kaçınmak mümkün müydü? Tabi ki evet! Kullanımdan önce nesne işaretçisinin kontrolünü eklemek yeterlidir. PrintStatus fonksiyonunu ekleyerek bu örneği değiştirelim:

//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void PrintStatus(CHello *pobject)
  {
   if(CheckPointer(pobject)==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(pobject.GetMessage());
  }

Şimdi bu fonksiyon GetMessage() yöntemini çağırır, CHello türündeki nesnenin işaretçisi fonksiyona geçirilir. Öncelikle, CheckPointer() fonksiyonunu kullanarak işaretçiyi kontrol eder. Harici bir parametre ekleyelim ve bir Uzman Danışman (EA) kodunu GetCriticalError_OnDemand.mq5 dosyasına kaydedelim.

//+------------------------------------------------------------------+
//|                                    GetCriticalError_OnDemand.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

input bool GetStop=false;// To get a critical error
//+------------------------------------------------------------------+
//| A simple class                                                   |
//+------------------------------------------------------------------+
class CHello
  {
private:
   string            m_message;
public:
                     CHello(){m_message="Starting...";}
   string            GetMessage(){return(m_message);}
  };
//---
CHello *pstatus;
//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void PrintStatus(CHello *pobject)
  {
   if(CheckPointer(pobject)==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(pobject.GetMessage());
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- calling a method to show status
   if(GetStop)
      pstatus.GetMessage();
   else
      PrintStatus(pstatus);
//--- printing a message if Expert Advisor has been initialized successfully
   Print(__FUNCTION__," The OnInit() function is completed");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+

Artık Uzman Danışmanı (EA) iki şekilde başlatabiliriz:

  1. Kritik bir hatayla (GetStop = doğru)
  2. Hatasız, ancak geçersiz işaretçiyle ilgili mesajla (GetStop = yanlış)

Varsayılan olarak, Uzman Danışmanın (EA) yürütülmesi başarılıdır ve "Uzmanlar" Günlüğünde aşağıdaki mesaj görünür:

GetCriticalError_OnDemand (EURUSD, H1) 15:01:57 PrintStatus 'nesne' değişkeni başlatılmadı!
GetCriticalError_OnDemand (EURUSD, H1) 15:01:57 OnInit fonksiyonu OnInit () tamamlandı

Böylece, işaretçiyi kullanmadan önce kontrol etmek, kritik hatalardan kaçınmayı sağlar.

Fonksiyonda kullanmadan önce her zaman işaretçi doğruluğunu kontrol edin.

Başlatılmamış Nesneyi Referansla Geçirme

Başlatılmamış nesneyi fonksiyonun giriş parametresi olarak iletirseniz ne olur? (nesne işaretçisine değil, referansa göre nesnenin kendisi). Sınıflar ve yapılar gibi karmaşık nesneler, bir ve işareti ile referans yoluyla iletilir. Bazı GetCriticalError_OnDemand.mq5'in kodlarını yeniden yazalım. PrintStatus() fonksiyonunu yeniden adlandıralım ve kodunu farklı bir şekilde yeniden yazalım.

//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void UnsafePrintStatus(CHello &object)
  {
   DebugBreak();
   if(CheckPointer(GetPointer(object))==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(object.GetMessage());
  }

Şimdi fark, bu türdeki değişkenin kendisinin CClassHello türünün nesne işaretçisi yerine bir giriş parametresi olarak referansla iletilmesidir. Bir Uzman Danışmanın (EA) yeni sürümünü GetCriticalError_Unsafe.mq5 olarak kaydedelim.

//+------------------------------------------------------------------+
//|                                      GetCriticalError_Unsafe.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

input bool GetStop=false;// To get a critical error
//+------------------------------------------------------------------+
//| A simple class                                                   |
//+------------------------------------------------------------------+
class CHello
  {
private:
   string            m_message;
public:
                     CHello(){m_message="Starting...";}
   string            GetMessage(){return(m_message);}
  };
//---
CHello *pstatus;
//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void UnsafePrintStatus(CHello &object)
  {
   DebugBreak();
   if(CheckPointer(GetPointer(object))==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(object.GetMessage());
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- calling a method to show status
   if(GetStop)
      pstatus.GetMessage();
   else
      UnsafePrintStatus(pstatus);
//--- printing a message if Expert Advisor has been initialized successfully
   Print(__FUNCTION__," The OnInit() function is completed");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+

GetCriticalError_OnDemand.mq5 ve GetCriticalError_Unsafe.mq5 (Uzman Danışmanları) arasındaki fark, fonksiyona parametre geçirme şeklinde görülebilir. İlk durumda, nesne işaretçisi fonksiyona geçirilir ve ikinci durumda, nesnenin kendisi referans yoluyla geçirilir. Her iki durumda da, nesne ve işaretçisi kullanılmadan önce fonksiyon, işaretçi doğruluğunu kontrol eder.

Bu, Uzman Danışmanların (EA) da aynı şekilde çalışacağı anlamına mı geliyor? Hayır, değil! Uzman Danışmanı (EA) GetStop=false parametresiyle başlatalım ve yine kritik bir hata alacağız. Gerçek şu ki, bir nesne referans yoluyla geçirilirse, başlatılmamış nesne bir parametre olarak geçirildiği için kritik hata bir fonksiyon çağrısı aşamasında ortaya çıkar. Komut dosyasını hata ayıklama modunda F5 düğmesini kullanarak doğrudan MetaEditor5'ten başlatırsanız doğrulayabilirsiniz.

Manuel kesme noktalarının kullanılmasını önlemek için, fonksiyonun içine DebugBreak () kesme noktasını ekleyerek fonksiyonu değiştirelim.

//+------------------------------------------------------------------+
//| Prints a message using a method of CHello type object            |
//+------------------------------------------------------------------+
void UnsafePrintStatus(CHello &object)
  {
   DebugBreak();
   if(CheckPointer(GetPointer(object))==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(object.GetMessage());
  }

Hata ayıklama modunda, Uzman Danışman (EA), DebugBreak() fonksiyonunun çağrısından önce kaldırılır. Referans yoluyla başlatılmamış bir nesne geçirilirse, durum için güvenli kod nasıl yazılır? Cevap basit, aşırı yükleme fonksiyonunu kullanmaktır.

Başlatılmamış bir nesnenin işaretçisi, fonksiyonun bir parametresi olarak referans yoluyla iletilirse, bu kritik bir hataya yol açar ve mql5 programını durdurur.

Güvenli Kod için Aşırı Yüklenmiş Fonksiyonları Kullanma

Harici kitaplığı kullanan geliştirici, giriş nesnelerinin doğruluğunu kontrol etmek zorunda kalırsa, bu çok uygunsuz olurdu. Kitaplık içinde gerekli tüm kontrolleri yapmak çok daha iyidir, bu, fonksiyon aşırı yüklemesi kullanılarak uygulanabilir.

UnsafePrintStatus() yöntemini fonksiyon aşırı yüklemesi ile uygulayalım ve bu fonksiyonun ilki nesnenin kendisi yerine geçirilen nesne işaretçisini kullanan, ikincisi referans yoluyla nesne geçişini kullanan iki versiyonunu yazalım. Her iki fonksiyon da aynı "PrintStatus" adına sahip olacaktır, ancak bu uygulama artık potansiyel olarak tehlikeli olmayacaktır.

//+------------------------------------------------------------------+
//| The safe printing of a message using the CHello object pointer     |
//+------------------------------------------------------------------+
void SafePrintStatus(CHello *pobject)
  {
   if(CheckPointer(pobject)==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(pobject.GetMessage());
  }
//+------------------------------------------------------------------+
//| Printing a message using the CHello object, passed by reference  |
//+------------------------------------------------------------------+
void SafePrintStatus(CHello &pobject)
  {
   DebugBreak();
   SafePrintStatus(GetPointer(pobject));
  }

Şimdi, nesne işaretçisinin geçirilmesi yoluyla fonksiyon çağrılırsa, doğruluk kontrolü yapılır ve kritik hata oluşmaz. Bir nesnenin referans yoluyla geçirilmesi ile aşırı yüklenmiş fonksiyonu çağırırsanız, önce GetPointer fonksiyonunu kullanarak nesne işaretçisini alırız ve ardından işaretçi tarafından bir nesnenin geçirilmesini kullanan güvenli kodu çağırırız.

Fonksiyonun çok daha kısa olan güvenli bir versiyonunu yeniden yazabiliriz, bunun yerine

void SafePrintStatus (CHello & pobject)
  (
   DebugBreak ();
   CHello * p = GetPointer (pobject);
   SafePrintStatus (p);
  )

kompakt versiyonunu yazalım:

void SafePrintStatus (CHello & object)
  (
   DebugBreak ();
   SafePrintStatus (GetPointer (object));
  )

Her iki versiyon da eşittir. İkinci versiyonu GetCriticalError_Safe.mq5 adıyla kaydedelim.

//+------------------------------------------------------------------+
//|                                        GetCriticalError_Safe.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

input bool GetStop=false;// To get a critical error
//+------------------------------------------------------------------+
//| A simple class                                                   |
//+------------------------------------------------------------------+
class CHello
  {
private:
   string            m_message;
public:
                     CHello(){m_message="Starting...";}
   string            GetMessage(){return(m_message);}
  };
//---
CHello *pstatus;
//+------------------------------------------------------------------+
//| The safe printing of a message using the CHello object pointer     |
//+------------------------------------------------------------------+
void SafePrintStatus(CHello *pobject)
  {
   if(CheckPointer(pobject)==POINTER_INVALID)
      Print(__FUNCTION__," the variable 'object' isn't initialized!");
   else Print(pobject.GetMessage());
  }
//+------------------------------------------------------------------+
//| Printing a message using the CHello object, passed by reference  |
//+------------------------------------------------------------------+
void SafePrintStatus(CHello &pobject)
  {
   DebugBreak();
   SafePrintStatus(GetPointer(pobject));
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- calling a method to show status
   if(GetStop)
      pstatus.GetMessage();
   else
      SafePrintStatus(pstatus);
//--- printing a message if Expert Advisor has been initialized successfully
   Print(__FUNCTION__," The OnInit() function is completed");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+

Farklı uygulamalarla (referansı geçirme yoluyla ve nesne işaretçisini geçirme yoluyla) iki fonksiyonu kullanırsanız, bu, aşırı yüklenmiş fonksiyonun güvenli çalışmasını sağlar.

Son olarak, fonksiyona parametre olarak aktarılan nesnelerin nasıl kullanılacağını öğrendik, şimdi şunu öğrenme zamanı:

İşaretçilere Ne Zaman İhtiyaç Duyarsınız?

Nesne işaretçileri, nesnelerin oluşturulması ve imha edilmesi sürecinin esnek bir yönetimini gerçekleştirmenize ve daha karmaşık soyut nesneler oluşturmanıza olanak tanır. Programı daha esnek hale getirir.

Bağlantılı Liste

Ancak bazı durumlarda farklı bir veri düzenleme yöntemi gerekir, bağlantılı liste bunlardan biridir. Bağlantılı liste CList sınıfı Standart Kitaplıkta mevcuttur, burada kendi örneklerimizi sunacağız. Bağlantılı liste, her liste öğesinin, varsa, sonraki ve önceki öğelerle bağlantılı olduğu anlamına gelir. Bu tür bağlantıları düzenlemek için liste öğelerinin (ListItem) nesne işaretçilerini kullanmak uygundur.

Bunun gibi bir listenin bir öğesini temsil edecek bir sınıf oluşturalım:

class CListItem
  {
private:
   int               m_ID;
   CListItem        *m_next;
   CListItem        *m_prev;
public:
                    ~CListItem();
   void              setID(int id){m_ID=id;}
   int               getID(){return(m_ID);}
   void              next(CListItem *item){m_next=item;}
   void              prev(CListItem *item){m_prev=item;}
   CListItem*        next(){return(m_next);}
   CListItem*        prev(){return(m_prev);}
  };

Listenin kendisi ayrı bir sınıfta düzenlenecektir:

//+------------------------------------------------------------------+
//| Linked list                                                      |
//+------------------------------------------------------------------+
class CList
  {
private:
   int               m_counter;
   CListItem        *m_first;
public:
                     CList(){m_counter=0;}
                    ~CList();
   void              addItem(CListItem *item);
   int               size(){return(m_counter);}
  };

CList sınıfı, birinci liste öğesinin m_first  işaretçisini içerir, diğer liste öğelerine erişim, CListItem() sınıfının sonraki next() ve prev() fonksiyonları aracılığıyla her zaman kullanılabilir. CList sınıfının iki ilginç fonksiyonu vardır. Birincisi, listeye yeni bir öğe ekleme fonksiyonudur.

//+------------------------------------------------------------------+
//| Adding of an item to the list                                    |
//+------------------------------------------------------------------+
CList::addItem(CListItem *item)
  {
//--- checking of a pointer, it should be correct
   if(CheckPointer(item)==POINTER_INVALID) return;
//--- increasing the number of list items
   m_counter++;
//--- if there isn't any items in the list
   if(CheckPointer(m_first)!=POINTER_DYNAMIC)
     {
      m_first=item;
     }
   else
     {
      //--- setting for first a pointer to the previous item
      m_first.prev(item);
      //--- saving a pointer of the current first item
      CListItem *p=m_first;
      //--- placing the input item on the place of the first element
      m_first=item;
      //--- for the first item in the list, setting a pointer to the next item 
      m_first.next(p);
     }
  }

Listeye eklenen her öğe birinci öğe olur, önceki birinci öğenin işaretçisi m_next t alanında saklanır. Böylece listeye ilk eklenen bir öğe listenin sonunda yer alacaktır. Son eklenen öğe, ilk olacaktır ve işaretçisi bir m_first değişkeninde depolanır. İkinci ilginç fonksiyon ise ~CList() yıkıcısıdır. Nesne yok edildiğinde çağırır, liste nesnelerinin doğru şekilde imha edilmesini sağlamalıdır. Bu çok basit şekilde yapılabilir:

//+------------------------------------------------------------------+
//| List destructor                                                  |
//+------------------------------------------------------------------+
CList::~CList(void)
  {
   int ID=m_first.getID();
   if(CheckPointer(m_first)==POINTER_DYNAMIC) delete(m_first);
   Print(__FUNCTION__," The first item with ID =",ID," is destroyed");
  }

m_first değişkeninin liste öğesinin doğru işaretçisini içeriyorsa, yalnızca birinci liste öğesinin kaldırıldığı görülebilir. Diğer tüm liste öğeleri çığ olarak kaldırılır, çünkü CListItem() sınıfı yıkıcısı sırayla doğru nesne kaldırılmasını üretir.

//+------------------------------------------------------------------+
//| Item destructor                                                  |
//+------------------------------------------------------------------+
CListItem::~CListItem(void)
  {
   if(CheckPointer(m_next)==POINTER_DYNAMIC)
     {
      delete(m_next);
      Print(__FUNCTION__," Removing an item with ID =",m_ID);
     }
   else
      Print(__FUNCTION__," The next item isn't defined for the item with ID=",m_ID);

  }

Yıkıcı içinde bir işaretçinin doğruluğu doğrulanır, belirtilmişse, m_next işaretçisine sahip nesne, delete() operatörü kullanılarak yok edilir. Yıkımdan önce, birinci liste öğesi yıkıcıyı çağırır, bu, ikinci öğeyi siler, ardından üçüncü öğenin silinmesine neden olur ve zincirin sonuna kadar böyle devam eder.

Listenin çalışması SampleList.mq5 komut dosyasında gösterilir. Bir listenin bildirimi (bir CListType değişkeni) OnStart () fonksiyonundadır. Bu liste otomatik olarak oluşturulacak ve başlatılacaktır. Listenin doldurulması bir liste içinde gerçekleştirilir ve ilk olarak her liste öğesi yeni operatörü kullanılarak dinamik olarak oluşturulur ve ardından listeye eklenir. 

void OnStart()
  {
//---
   CList list;
   for(int i=0;i<7;i++)
     {
      CListItem *item=new CListItem;
      item.setID(i);
      list.addItem(item);
     }
     Print("There are ",list.size()," items in the list");
  }

Komut dosyasını başlatın ve "Uzmanlar" günlüğünde aşağıdaki mesajları göreceksiniz.

2010.03.18 11:22:05 SampleList (EURUSD, H1) CList:: ~ CList ID=6 olan birinci öğe yok edildi
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem ID = 6 olan bir öğeyi kaldırma
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem ID = 5 olan bir öğeyi kaldırma
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem ID = 4 olan bir öğeyi kaldırma
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem ID = 3 olan bir öğeyi kaldırma
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem ID = 2 olan bir öğeyi kaldırma
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem ID = 1 olan bir öğeyi kaldırma
2010.03.18 11:22:05 SampleList (EURUSD, H1) CListItem:: ~ CListItem ID=0 olan öğe için sonraki öğe tanımlı değil
2010.03.18 11:22:05 SampleList (EURUSD, H1) Listede 7 öğe var

Kodu dikkatli bir şekilde incelediyseniz, ID=0 olan öğenin bir sonraki öğeye sahip olmaması şaşırtıcı değildir. Bununla birlikte, işaretçilerin kullanımının programların yazılmasını kolay ve okunabilir hale getirmesinin tek bir nedeni üzerinde durduk. İkinci bir neden daha var ve bu şöyle adlandırılır:

Polimorfizm

Aynı türe ait farklı nesneler için aynı genellikle aynı fonksiyonu uygulamak gereklidir. Örneğin Çizgi, Üçgen, Dikdörtgen ve Daire gibi basit nesneler vardır. Farklı görünmelerine rağmen, ortak bir özellikleri vardır, bunlar çizilebilirdir. Bir CShape temel sınıfı oluşturalım ve onu her tür geometrik şekil için soyundan gelenleri oluşturmak için kullanalım.


Eğitim amaçları için, temel sınıf ve bunun soyundan gelenler minimal bir fonksiyona sahiptir.

//+------------------------------------------------------------------+
//| The base class for a Shape object                                |
//+------------------------------------------------------------------+
class CShape
  {
private:
   int               m_type;
public:
                     CShape(){m_type=0;}
   void              Draw();
   string            getTypeName(){return("Shape");}
  };
//+------------------------------------------------------------------+
//| The class for a Line object                                      |
//+------------------------------------------------------------------+
class CLine:public CShape
  {
private:
   int               m_type;
public:
                     CLine(){m_type=1;}
   void              Draw();
   string            getTypeName(){return("Line");}
  };
//+------------------------------------------------------------------+
//| The class for a Triangle object                                  |
//+------------------------------------------------------------------+
class CTriangle:public CShape
  {
private:
   int               m_type;
public:
                     CTriangle(){m_type=2;}
   void              Draw();
   string            getTypeName(){return("Triangle");}
  };
//+------------------------------------------------------------------+
//| The class for a Rectangle object                                 |
//+------------------------------------------------------------------+
class CRectangle:public CShape
  {
private:
   int               m_type;
public:
                     CRectangle(){m_type=3;}
   void              Draw();
   string            getTypeName(){return("Rectangle");}
  };
//+------------------------------------------------------------------+
//| The class for a Cirlce object                                    |
//+------------------------------------------------------------------+
class CCircle:public CShape
  {
private:
   int               m_type;
public:
                     CCircle(){m_type=4;}
   void              Draw();
   string            getTypeName(){return("Circle");}
  };

Üst CShape sınıfı, soyundan gelenlerde geçersiz kılınan iki fonksiyon içerir - bir Draw() ve getTypeName(). Draw() fonksiyonu bir şekil çizmeye yöneliktir ve getTypeName() fonksiyonu, şeklin bir dize açıklamasını verir.

CShape temel türünün işaretçilerini içeren ve farklı sınıflar için bir işaretçinin değerlerini belirten bir *shapes[] dizisi oluşturalım.

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- an array of pointers of objects of CShape type
   CShape *shapes[];
//--- resizing of an array 
   ArrayResize(shapes,5);
//--- filling of a pointers array
   shapes[0]=new CShape;
   shapes[1]=new CLine;
   shapes[2]=new CTriangle;
   shapes[3]=new CRectangle;
   shapes[4]=new CCircle;
//--- printing the type of each array element
   for(int i=0;i<5;i++)
     {
      Print(i,shapes[i].getTypeName());
     }
//--- deleting all objects in the array
   for(int i=0;i<5;i++) delete(shapes[i]);
  }

for() döngüsünün içinde, *shapes[] dizisinin her öğesi için getTypeName() yöntemini çağırırız. Her türetilen sınıfın getTypleName() fonksiyonunun kendi uygulamasına sahip olmasına rağmen ilk seferde bir temel sınıfın getTypeName() fonksiyonunun listedeki her nesne için çağrılması sizi şaşırtabilir.

2010.03.18 14:06:18 DemoPolimorfizm (EURUSD, H1) 4 Şekil
2010.03.18 14:06:18 DemoPolimorfizm (EURUSD, H1) 3 Şekil
2010.03.18 14:06:18 DemoPolimorfizm (EURUSD, H1) 2 Şekil
2010.03.18 14:06:18 DemoPolimorfizm (EURUSD, H1) 1 Şekil
2010.03.18 14:06:18 DemoPolimorfizm (EURUSD, H1) 0 Şekil

Bu gerçeğin açıklaması şudur: *shapes [] dizisi, CShape türünde bir işaretçi dizisi olarak bildirilir, ve bu nedenle her dizi nesnesi, bunun soyundan gelen farklı bir uygulamaya sahip olsa bile, bir temel sınıfın getTypeName() yöntemini çağırır. Programın yürütüldüğü anda gerçek nesne türüne (soyundan gelen) karşılık gelen getTypeName() fonksiyonunu çağırmak için, bu fonksiyonu bir temel sınıfta sanal bir fonksiyon olarak bildirmek gerekir.

Bir üst CShape sınıfının bildirimindeki getTypeName() fonksiyonuna sanal anahtar sözcüğünü ekleyelim.

class CShape
  (
private:
   int m_type;
public:
                     CShape () (m_type = 0;)
   void Draw ();
   virtual string getTypeName () (return ("Shape");)
  )

ve komut dosyasını yeniden başlatalım. Şimdi sonuçlar beklenenlerle tutarlıdır:

2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 4 Daire
2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 3 Dikdörtgen
2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 2 Üçgen
2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 1 Satır
2010.03.18 15:01:11 DemoPolymorphism (EURUSD, H1) 0 Şekil

Bu nedenle, bir temel sınıftaki sanal bir fonksiyonun bildirimi, programın yürütülmesi sırasında soyundan gelenin aynı fonksiyonun çağrılmasına izin vermiştir. Artık türetilmiş sınıfların her biri için tam özellikli Draw() fonksiyonunu uygulayabiliriz.

Çalışmasının bir örneği, grafikte rastgele şekiller gösteren ekli DrawManyObjects.mq5 komut dosyasında bulunabilir.

Sonuç

Yani, şimdi özetleme zamanı. MQL5'te nesnelerin oluşturulması ve yok edilmesi otomatik olarak gerçekleştirilir, bu nedenle işaretçileri yalnızca gerçekten ihtiyaç duyulduğunda ve bunlarla nasıl çalışacağınızı anlıyorsanız kullanmalısınız.

Ancak, bunu işaretçileri kullanmadan yapamıyorsanız, kullanmadan önce işaretçi doğruluğunu CheckPointer() kullanarak kontrol ettiğinizden emin olun - bu durumlar için özel olarak eklenmiştir.

Son bir şey: MQL5'te işaretçiler, C++'da kullanıldığı gibi gerçek bellek işaretçileri değildir, bu nedenle bunları giriş parametreleri olarak DLL'ye geçirmemelisiniz.

MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/36

Yeni Başlayanlar için MQL5'te Özel Göstergeler Yeni Başlayanlar için MQL5'te Özel Göstergeler
Herhangi bir yeni konu, bir acemi için karmaşık ve öğrenmesi zor görünür. Bildiğimiz konular ise bize çok basit ve anlaşılır gelir. Ancak, herkesin bir şeyi sıfırdan ve hatta ana dilimizden öğrenmek zorunda olduğunu hatırlamıyoruz. Aynısı, kişinin kendi alım satım stratejilerini geliştirmesi için geniş olanaklar sunan MQL5 programlama dili için de geçerlidir - bunu temel kavramlardan ve en basit örneklerden öğrenmeye başlayabilirsiniz. Teknik bir göstergenin MetaTrader 5 istemci terminali ile etkileşimi, bu makalede basit özel gösterge SMA örneğinde ele alınmaktadır.
MQL5'e Giriş: Basit Uzman Danışman (EA) ve Özel Gösterge nasıl yazılır MQL5'e Giriş: Basit Uzman Danışman (EA) ve Özel Gösterge nasıl yazılır
MetaTrader 5 İstemci Terminaline dahil edilen MetaQuotes Programlama Dili 5 (MQL5), MQL4'e kıyasla birçok yeni imkana ve daha yüksek performansa sahiptir. Bu makale, bu yeni programlama dili hakkında bilgi edinmenize yardımcı olacaktır. Uzman Danışman ve Özel Göstergenin nasıl yazılacağına dair basit örnekler bu makalede sunulmuştur. Bu örnekleri anlamak için gerekli olan MQL5 dilinin bazı ayrıntılarını da ele alacağız.
OnTrade() fonksiyonunu kullanarak Uzman Danışmanda (EA) alım satım etkinliklerinin işlenmesi OnTrade() fonksiyonunu kullanarak Uzman Danışmanda (EA) alım satım etkinliklerinin işlenmesi
MQL5, çeşitli türlerdeki etkinliklerle (zamanlayıcı etkinlikleri, alım satım etkinlikleri, özel etkinlikler vb.) çalışmak da dahil olmak üzere bir dizi yenilik getirmiştir. Etkinlikleri işleme becerisi, otomatik ve yarı otomatik alım satım için tamamen yeni tür programlar oluşturmanıza olanak tanır. Bu makalede, alım satım etkinliklerini ele alacağız ve Alım Satım etkinliğini işleyecek olan OnTrade() fonksiyonu için bazı kodlar yazacağız.
Yeni Başlayanlar için MQL5: Uzman Danışmanlarda Teknik Göstergeleri Kullanma Rehberi Yeni Başlayanlar için MQL5: Uzman Danışmanlarda Teknik Göstergeleri Kullanma Rehberi
Bir Uzman Danışmanda yerleşik veya özel bir göstergenin değerlerini elde etmek için, öncelikle ilgili işlev kullanılarak tanıtıcı değeri oluşturulmalıdır. Makaledeki örnekler, kendi programlarınızı oluştururken teknik göstergelerin nasıl kullanılacağını gösterir. Bu makale, MQL5 dilinde oluşturulan göstergeleri açıklar. Alım satım stratejileri geliştirme konusunda fazla deneyimi olmayanlar için tasarlanmıştır ve sunulan fonksiyon kitaplığını kullanarak göstergelerle çalışmanın basit ve net yollarını sunar.