English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Nesne Yönelimli Programlamanın Temelleri

Nesne Yönelimli Programlamanın Temelleri

MetaTrader 5Örnekler | 9 Aralık 2021, 12:44
120 0
Dmitry Fedoseev
Dmitry Fedoseev

 

Giriş

nesne yönelimli programlamayı (OOP) öğrenmeye başlayan herkesin ilk olarak polimorfizm, kapsülleme, aşırı yük ve kalıtım gibi kelimelerle karşılaştığını varsayabiliriz. Belki birisi hazır sınıflara baktı ve bu polimorfizmin veya kapsüllemenin gerçekte nerede olduğunu anlamaya çalıştı... Büyük olasılıkla bu, OOP öğrenme sürecinin sonu olabilir.

Aslında her şey göründüğü gibi çok daha basittir. OOP'yi kullanmak için bu kelimelerin ne anlama geldiğini bilmenize gerek yok - ne dendiğini bile bilmeden sadece OOP özelliklerini kullanabilirsiniz. Yine de, bu makaleyi okuyacak olan herkesin sadece OOP'yi nasıl kullanacağını öğrenmekle kalmayıp, aynı zamanda bu kelimelerin anlamlarını da netleştireceğini umuyorum.

 

Fonksiyon Kitaplıkları Oluşturma

OOP'nin birinci ve en basit uygulaması, sık kullanılan fonksiyonlardan oluşan kendi kitaplıklarınızı oluşturmaktır. Elbette, bu fonksiyonları bir içerme dosyasında (mqh) depolayabilirsiniz. Bir fonksiyona ihtiyacınız olduğunda, sadece bir dosya ekleyin ve bu fonksiyonu çağırın. Ancak, yeterince uzun programlarsanız, çok sayıda fonksiyonu toplayabilirsiniz, böylece adlarını ve amaçlarını hatırlamak zor olur.

Fonksiyonları amaca göre kategorilere ayırarak farklı dosyalarda toplayabilirsiniz. Örneğin, dizilerle çalışma fonksiyonları, dizeyle çalışma fonksiyonları, sıraları hesaplama fonksiyonları vb. Son cümlede "kategori" kelimesi "sınıflar" kelimesi ile değiştirilebilir. Anlam aynı kalır, ancak konuya daha da yaklaşırız - Nesne Yönelimli Programlama.

Böylece, fonksiyonlar sınıflara ayrılabilir: dizilerle çalışacak fonksiyonlar sınıfı, dizelerle çalışacak fonksiyonlar sınıfı, sıraları saymak için fonksiyonlar sınıfı vb. "Sınıf" kelimesi, temel kavram olduğu için bizi OOP konusuna yaklaştırır. Çeşitli referans kitaplarda, sözlüklerde ve ansiklopedilerde (örneğin Wikipedia) "programlama sınıfının" ne olduğunu araştırabilirsiniz.

Nesne yönelimli programlamada sınıf, kendisinin örneklerini oluşturmak için plan olarak kullanılan bir yapıdır.

Belki de ilk izlenim, "polimorfizm", "kapsülleme" vb. kelimelerde olduğu gibi aynı olacaktır. Şu an için 'sınıf' adıyla bir dizi fonksiyon ve değişkeni kastedeceğiz. Bir kitaplık oluşturmak için sınıfın kullanılması durumunda - işlenmiş veri türüne veya işlenmiş nesnelerin, dizilerin, dizelerin, sıraların türüne göre gruplandırılmış bir dizi fonksiyon ve değişken.

 

Program İçinde Bir Program

Forumda benzer pek çok soru vardı (ve olacak) - bir Uzman Danışmandan (EA) bir komut dosyası nasıl çağrılır? Üçüncü taraf araçları kullanmaktan uzak dururken, bu görev, komut dosyası kodunun Uzman Danışman (EA) kodunun içine yerleştirilmesiyle gerçekleştirilir. Aslında, bu zor bir görev değil, ancak bir komut dosyası EA ile aynı değişken ve fonksiyon adlarını kullanabilir, bu nedenle komut dosyası kodunu ayarlamanız gerekir. Değişiklikler karmaşık değil, ancak muhtemelen hacim olarak önemlidir.

Bu komut dosyasını ayrı bir bağımsız program olarak adlandırmak harika olacaktır! Bu, komut dosyasını bir sınıf olarak programlayacak ve ardından bu sınıfı kullanacaksanız mümkündür. İş miktarı sadece birkaç kod satırı ile artırılacaktır. Bu durumda bir sınıf, fonksiyonları işlenen verinin türüne göre değil, amaçlarına göre birleştirecektir. Örneğin: bekleyen emirleri silmek için bir sınıf, pozisyon açmak veya emir vermek için bir sınıf, grafik nesnelerle çalışmak için bir sınıf vb.

Sınıfın önemli bir özelliği, içinde bulunduğu alandan ayırt edilmesidir. Sınıf, bir işletim sisteminde çalışan bir program gibidir: birden fazla program aynı anda, ancak birbirinden bağımsız olarak kendi başlarına çalışabilir. Bu nedenle sınıf, içinde bulunduğu alandan farklı olduğu için "program içinde bir program" olarak adlandırılabilir.

 

Bir Sınıfın Görünümü ve Hissi

Sınıf oluşturma, sınıf kelimesiyle başlar, ardından sınıf adı gelir ve ardından tüm sınıf kodu küme parantezi içine alınır:

class CName 
  {
   // Here is the entire code of the class
  };
Dikkat! Kapanış parantezinden sonra noktalı virgül koymayı unutmayın.

 

Görünür ve Gizli (Kapsülleme)

Herhangi bir program alırsanız, bunun çeşitli fonksiyonlar içerdiğini biliyoruz. Bu fonksiyonlar iki türe ayrılabilir: ana ve yardımcı. Ana fonksiyonlar, bir programın aslında oluştuğu fonksiyonlardır. Bu fonksiyonlar, kullanıcının bilmesi gerekmeyen birçok başka fonksiyonu gerektirebilir. Örneğin, istemci terminalinde bir pozisyon açmak için yatırımcının Yeni Emir iletişim kutusunu açması, hacmi,​Zararı Durdur ve Kar Al değerlerini girmesi ve ardından "Satın Al" veya "Sat" düğmesine tıklaması gerekir.

Ancak düğmeye tıklamak ve bir pozisyon açmak arasında gerçekte neler olup bittiğini sadece terminal geliştiricileri kesin olarak söyleyebilir. Terminalin birçok işlem yaptığını varsayabiliriz: hacim konumunu kontrol eder,​Zararı Durdur ve Kar Al değerlerini kontrol eder, ağ bağlantısını kontrol eder vb. Çok sayıda prosedür gizlidir veya başka bir deyişle kapsüllenmiştir. Benzer şekilde, bir sınıfta kodu parçalara ayırabilirsiniz (fonksiyonlar ve değişkenler) - bunlardan bazıları bir sınıf kullanırken kullanılabilir olacak ve bazıları gizlenecektir.

Kapsülleme seviyeleri şu anahtar sözcükler kullanılarak tanımlanır: özel, korumalı ve herkese açık. Korumalı ve özel arasındaki fark biraz sonra ele alınacaktır, ancak önce özel ve herkese açık anahtar kelimelerine değineceğiz. Böylece, basit bir sınıf şablonu aşağıdaki formu alır:

class CName 
  {
private:
   // Variables and functions available only inside the class
public:
   // Variables and functions available outside the class
  };
Bu, OOP'den yararlanmak için yeterlidir. Kodunuzu doğrudan Uzman Danışmana (EA) (Komut Dosyası veya Gösterge) yazmak yerine önce bir sınıf oluşturun ve ardından her şeyi bu sınıfa yazın. Daha sonra özel ve herkese açık bölümleri arasındaki farkı pratik bir örnek üzerinde ele alacağız.

 

Kitaplık Oluşturma Örneği

Yukarıda sunulan sınıf şablonu, bir fonksiyon kitaplığı oluşturmak için kullanılabilir. Dizilerle çalışmak için bir sınıf oluşturalım. Bir diziyi kullanırken ortaya çıkabilecek en yaygın görevler diziye yeni bir öğe eklemek ve verilen değere sahip öğenin dizide olmaması şartıyla yeni bir öğe eklemektir.

Diziye öğe ekleyen fonksiyonu AddToEnd() ve diziye benzersiz öğe ekleyen fonksiyonu AddToEndIfNotExists() olarak adlandıralım. AddToEndIfNotExists() fonksiyonunda önce, eklenen öğenin dizide zaten var olup olmadığını kontrol etmemiz ve yoksa AddToEnd() fonksiyonunu kullanmamız gerekecektir. Dizide bir öğenin zaten var olup olmadığını kontrol eden fonksiyon, yardımcı olarak kabul edilecektir, bu nedenle bunu özel bölüme ve diğer tüm fonksiyonları herkese açık bölüme yerleştireceğiz. Sonuç olarak, aşağıdaki sınıfı elde edeceğiz:

class CLibArray 
  {
private:
   // Check if an element with required value exists in array
   int Find(int &aArray[],int aValue) 
     {
      for(int i=0; i<ArraySize(aArray); i++) 
        {
         if(aArray[i]==aValue) 
           {
            return(i); // Element exists, return index of element
           }
        }
      return(-1);  // No such element, return -1
     }
public:
   // Add to end of array
   void AddToEnd(int &aArray[],int aValue) 
     {
      int m_size=ArraySize(aArray);
      ArrayResize(aArray,m_size+1);
      aArray[m_size]=aValue;
     }
   // Add to end of array if there is no such value in array already
   void AddToEndIfNotExistss(int &aArray[],int aValue) 
     {
      if(Find(aArray,aValue)==-1) 
        {
         AddToEnd(aArray,aValue);
        }
     }
  };
 

Yükleme Sınıfı

Bir sınıfı kullanmak için bunun yüklenmiş olması gerekir. Bir sınıf ayrı bir dosyada bulunuyorsa, bu dosyayı eklemeniz

#include <OOP_CLibArray_1.mqh>

ve sonra bu sınıfı yüklemeniz gerekir. Sınıf yükleme, değişken bildirimine benzer:

CLibArray ar;

Önce sınıfın adı, ardından bu örneğe atıfta bulunacak bir işaretçinin adı gelir. Yüklendikten sonra sınıf bir nesne haline gelir. Bir nesnenin herhangi bir fonksiyonunu kullanmak için işaretçi adını, noktayı ve ardından fonksiyon adını yazın. Noktayı yazdıktan sonra, açılır bir sınıf fonksiyonları listesi açılacaktır (Şekil 1).

Şekil 1. Fonksiyon Listesi
Şekil 1. Fonksiyon Listesi

Açılır liste sayesinde fonksiyonların adlarını hatırlamanıza gerek yoktur - adlar listesinde gezinebilir ve fonksiyonun amacını hatırlayabilirsiniz. Bu, yalnızca dosyalarda fonksiyon toplamak yerine kitaplıklar oluşturmak için sınıfları kullanmanın en büyük avantajıdır.

Toplama fonksiyonu durumunda, fonksiyon adının ilk birkaç harfini yazdığınızda, açılır liste, dahil edilen tüm kitaplıklardaki tüm fonksiyonları ve sınıfları kullandığınızda yalnızca belirtilen sınıfla ilgili fonksiyonları gösterir. Ayrıca Find() fonksiyonunun listelenmediğine dikkat edin - bu, özel ve herkese açık bölümler arasındaki farktır. Fonksiyon özel bölüme yazılmıştır ve bu nedenle kullanılamaz.

 

Farklı Veri Türleri İçin Evrensel Kitaplık Oluşturma (Aşırı Yükleme)

Bu noktada kitaplığımız sadece int türündeki diziler ile çalışan fonksiyonlar içermektedir. int türü dizilere ek olarak, şu türlerdeki dizilere kitaplık fonksiyonları uygulamamız gerekebilir: uint, long, ulong vb. Diğer veri türlerinin dizileri için kendi fonksiyonlarını yazmamız gerekir. Ancak, bu fonksiyonlara başka adlar vermeniz gerekmez - geçirilen parametrenin türüne veya parametre setine bağlı olarak (bu örnekte, parametrelerin türüne bağlı olarak) doğru fonksiyon otomatik olarak seçilir. Sınıfı long türden dizilerle çalışma fonksiyonlarıyla tamamlayalım:

class CLibArray 
  {
private:
   // Для int. Check if an element with required value exists in array
   int Find(int &aArray[],int aValue)
     {
      for(int i=0; i<ArraySize(aArray); i++) 
        {
         if(aArray[i]==aValue) 
           {
            return(i); // Element exists, return index of element
           }
        }
      return(-1); // No such element, return -1
     }
   // For long. Check if an element with required value exists in array
   int Find(long &aArray[],long aValue) 
     {
      for(int i=0; i<ArraySize(aArray); i++) 
        {
         if(aArray[i]==aValue) 
           {
            return(i); // Element exists, return index of element
           }
        }
      return(-1); // No such element, return -1
     }
public:
   // For int. Add to end of array
   void AddToEnd(int &aArray[],int aValue) 
     {
      int m_size=ArraySize(aArray);
      ArrayResize(aArray,m_size+1);
      aArray[m_size]=aValue;
     }
   // For long. Add to end of array
   void AddToEnd(long &aArray[],long aValue) 
     {
      int m_size=ArraySize(aArray);
      ArrayResize(aArray,m_size+1);
      aArray[m_size]=aValue;
     }
   // For int. Add to end of array if there is no such value in array already
   void AddToEndIfNotExistss(int &aArray[],int aValue) 
     {
      if(Find(aArray,aValue)==-1) 
        {
         AddToEnd(aArray,aValue);
        }
     }
   // For long. Add to end of array if there is no such value in array already
   void AddToEndIfNotExistss(long &aArray[],long aValue) 
     {
      if(Find(aArray,aValue)==-1) 
        {
         AddToEnd(aArray,aValue);
        }
     }
  };
Şimdi aynı adı kullanarak farklı fonksiyonlara sahibiz. Bu fonksiyonlar, bir ad birden fazla fonksiyonla yüklendiğinden, yani aşırı yüklendiğinden aşırı yüklenmiş olarak adlandırılır.

Bu örneği, bu makalenin ekindeki OOP_CLibArray_1.mqh dosyasında bulabilirsiniz.

 

Sınıf Gösteriminin Başka Bir Yolu

Yukarıdaki örneklerde tüm fonksiyonlar sınıf içinde yazılmıştır. Çok sayıda fonksiyonunuz varsa ve her biri oldukça büyükse, bu tür bir gösterim çok rahat olmayabilir. Bu gibi durumlarda fonksiyonları sınıfın dışına yerleştirebilirsiniz. Sınıfın içine sadece parametreleri olan fonksiyonların adlarını yazarsınız ve fonksiyonlar sınıfın dışında tam olarak tanımlanır. Ayrıca, fonksiyonun belirli bir sınıfa ait olduğunu belirtmelisiniz: önce sınıf adını yazın, ardından iki nokta üst üste koyun ve fonksiyon adını yazın:

class CLibArray 
  {
private:
   int               Find(int  &aArray[],int  aValue);
   int               Find(long &aArray[],long aValue);
public:
   void              AddToEnd(int  &aArray[],int  aValue);
   void              AddToEnd(long &aArray[],long aValue);
   void              AddToEndIfNotExistss(int  &aArray[],int  aValue);
   void              AddToEndIfNotExistss(long &aArray[],long aValue);
  };
//---
int CLibArray::Find(int &aArray[],int aValue) 
  {
   for(int i=0; i<ArraySize(aArray); i++) 
     {
      if(aArray[i]==aValue) 
        {
         return(i);
        }
     }
   return(-1);
  }
//---
int CLibArray::Find(long &aArray[],long aValue) 
  {
   for(int i=0; i<ArraySize(aArray); i++) 
     {
      if(aArray[i]==aValue) 
        {
         return(i);
        }
     }
   return(-1);
  }
//---
void CLibArray::AddToEnd(int &aArray[],int aValue) 
  {
   int m_size=ArraySize(aArray);
   ArrayResize(aArray,m_size+1);
   aArray[m_size]=aValue;
  }
//---
void CLibArray::AddToEnd(long &aArray[],long aValue) 
  {
   int m_size=ArraySize(aArray);
   ArrayResize(aArray,m_size+1);
   aArray[m_size]=aValue;
  }
//---
void CLibArray::AddToEndIfNotExistss(int &aArray[],int aValue) 
  {
   if(Find(aArray,aValue)==-1) 
     {
      AddToEnd(aArray,aValue);
     }
  }
//---
void CLibArray::AddToEndIfNotExistss(long &aArray[],long aValue) 
  {
   if(Find(aArray,aValue)==-1) 
     {
      AddToEnd(aArray,aValue);
     }
  }

Böyle bir gösterimle, sınıf kompozisyonunun tam bir resmini elde edebilir ve gerekirse ayrı fonksiyonlara daha yakından bakabilirsiniz.

Bu örneği, bu makalenin ekindeki OOP_CLibArray_2.mqh dosyasında bulabilirsiniz.

 

Sınıfta Değişkenleri Belirtme

Daha önce bahsedilen örneği ele almaya devam edelim. Doğrudan dosyada kodlama ile sınıf içinde kodlama arasında bir fark vardır. Doğrudan dosyada değerler içeren değişkenleri ​belirttiğiniz gibi atayabilirsiniz:

int Var = 123;

Bir sınıfta bir değişken bildirirseniz bunu yapamazsınız - değerler ​bir sınıfın bazı fonksiyonlarını çalıştırırken atanmalıdır. Bu nedenle, öncelikle parametreleri sınıfa geçirmeniz (yani, sınıfı çalışmaya hazırlamanız) gerekir. Bu fonksiyonu Init() olarak adlandıralım.

Bunu pratik bir örnek üzerinde düşünün.

 

Komut Dosyasını Sınıfa Dönüştürme Örneği

Bekleyen emirleri silen bir komut dosyası olduğunu varsayalım (ekteki OOP_sDeleteOrders_1.mq5 dosyasına bakın).

// Include file to use the CTrade class from standard delivery
#include <Trade/Trade.mqh>

// External parameters

// Select symbol. true  - delete orders for all symbols, 
//                false - only for symbol of chart, where the script is running
input bool AllSymbol=false;

// Select types of orders to delete
input bool BuyStop       = false;
input bool SellStop      = false;
input bool BuyLimit      = false;
input bool SellLimit     = false;
input bool BuyStopLimit  = false;
input bool SellStopLimit = false;

// Load the CTrade class
CTrade Trade;
//---
void OnStart()
  {
// Variable to check function result
   bool Ret=true;
// Loop by all orders in terminal
   for(int i=0; i<OrdersTotal(); i++)
     {
      ulong Ticket=OrderGetTicket(i); // Select order and get its ticket
                                      // Successfully selected
      if(Ticket>0)
        {
         long Type=OrderGetInteger(ORDER_TYPE);
         // Check order type
         if(Type == ORDER_TYPE_BUY_STOP && !BuyStop) continue;
         if(Type == ORDER_TYPE_SELL_STOP && !SellStop) continue;
         if(Type == ORDER_TYPE_BUY_LIMIT && !BuyLimit) continue;
         if(Type == ORDER_TYPE_SELL_LIMIT && !SellLimit) continue;
         if(Type == ORDER_TYPE_BUY_STOP_LIMIT && !BuyStopLimit) continue;
         if(Type == ORDER_TYPE_SELL_STOP_LIMIT && !SellStopLimit) continue;
         // Check symbol
         if(!AllSymbol && Symbol()!=OrderGetString(ORDER_SYMBOL)) continue;
         // Delete
         if(!Trade.OrderDelete(Ticket))
           {
            Ret=false; // Failed to delete
           }
        }
      // Failed to select order, unknown result,
      // function ended up with error
      else
        {
         Ret=false;
         Print("Error selecting order");
        }
     }

   if(Ret)
     {
      Alert("Script ended successfully");
     }
   else    
     {
      Alert("Script ended up with error, see details. in Journal");
     }
  }

Komut dosyası, çeşitli emir türlerini etkinleştirmeyi ve emirlerin silineceği sembolü seçmeyi sağlayan harici parametrelere sahiptir (komut dosyasının çalıştığı tüm semboller veya grafiğin sembolü).

Bu komut dosyasını COorderDelete adlı sınıfa dönüştürün. Özel bölümde, komut dosyasında bildirilen aynı değişkenleri harici parametreler olarak, ancak değişken adlarını "m_" ile ("üye" kelimesinden, yani sınıfın üyesinden) bildirelim. Ön ek eklemek ​​gerekli değildir, ancak değişkenleri kolayca ayırt etmeyi sağladığı için çok uygundur. Böylece sınıf alanı ile sınırlı değişkenlerle uğraştığımızdan emin olabiliriz. Ayrıca, değişken bildiriminin global kapsamda bildirilen değişkeni gizlediğine dair derleyici uyarıları almazsınız.

Global kapsamda, sınıf tanımında, fonksiyon gövdesinde aynı değişken adlarını kullanmak bir hata değildir, fakat programın anlaşılmasını zorlaştırır, bu yüzden bu gibi durumlarda derleyici uyarı verir. Değişkenleri değerlerle atamak için ​bu değişkenlere (ve komut dosyasının harici parametrelerine) karşılık gelen parametrelerle Init() fonksiyonunu yazın. Bu sınıfı kullanıyorsanız, önce Init() fonksiyonunu çağırmanız ve buna harici parametreler geçirmeniz gerekir. Komut dosyası kodunun geri kalanı değişmeden kalır. Tek istisna - doğrudan harici parametreleri kullanmak yerine, sınıf içinde bildirilen değişkenleri kullanmalısınız.

Böylece aşağıdaki sınıfı elde ederiz:

#include <Trade/Trade.mqh> 

class COrderDelete 
  {

private:
   // Variables for parameters
   bool              m_AllSymbol;
   bool              m_BuyStop;
   bool              m_SellStop;
   bool              m_BuyLimit;
   bool              m_SellLimit;
   bool              m_BuyStopLimit;
   bool              m_SellStopLimit;
   // Load the CTrade class
   CTrade            m_Trade;
public:
   // Function to set parameters
   void Init(bool aAllSymbol,bool aBuyStop,bool aSellStop,bool aBuyLimit,bool aSellLimit,bool aBuyStopLimit,bool aSellStopLimit) 
     {
      // Set parameters
      m_AllSymbol    =aAllSymbol;
      m_BuyStop      =aBuyStop;
      m_SellStop     =aSellStop;
      m_BuyLimit     =aBuyLimit;
      m_SellLimit    =aSellLimit;
      m_BuyStopLimit =aBuyStopLimit;
      m_SellStopLimit=aSellStopLimit;
     }
   Main function to delete orders
   bool Delete() 
     {
      // Variable to check function result
      bool m_Ret=true;
      // Loop by all orders in terminal
      for(int i=0; i<OrdersTotal(); i++) 
        {
         // Select order and get its ticket
         ulong m_Ticket=OrderGetTicket(i);
         // Successfully selected
         if(m_Ticket>0) 
           {
            long m_Type=OrderGetInteger(ORDER_TYPE);
            // Check order type
            if(m_Type == ORDER_TYPE_BUY_STOP && !m_BuyStop) continue;
            if(m_Type == ORDER_TYPE_SELL_STOP && !m_SellStop) continue;
            if(m_Type == ORDER_TYPE_BUY_LIMIT && !m_BuyLimit) continue;
            if(m_Type == ORDER_TYPE_SELL_LIMIT && !m_SellLimit) continue;
            if(m_Type == ORDER_TYPE_BUY_STOP_LIMIT && !m_BuyStopLimit) continue;
            if(m_Type == ORDER_TYPE_SELL_STOP_LIMIT && !m_SellStopLimit) continue;
            // Check symbol/s61>
            if(!m_AllSymbol && Symbol()!=OrderGetString(ORDER_SYMBOL)) continue;
            // Delete
            if(!m_Trade.OrderDelete(m_Ticket)) 
              {
               m_Ret=false; // Failed to delete
              }
           }
         // Failed to select order, unknown result,
         // function ended up with error
         else 
           {
            m_Ret=false;
            Print("Error selecting order");
           }
        }
      // Return function result
      return(m_Ret);
     }
  };
Bu sınıfın örneğini bu makalenin ekindeki OOP_CDeleteOrder_1.mqh dosyasında bulabilirsiniz. Bu sınıfı kullanan komut dosyası minimuma indirilir (harici parametreler, yükleme sınıfı, Init() ve Delete() yöntemlerini çağırın):
// External parameters

// Select symbol. true  - delete orders for all symbols, 
//                false - only for symbol of chart, where the script is running
input bool AllSymbol=false;

// Select types of orders to delete
input bool BuyStop       = false;
input bool SellStop      = false;
input bool BuyLimit      = false;
input bool SellLimit     = false;
input bool BuyStopLimit  = false;
input bool SellStopLimit = false;

// Include file with class
#include <OOP_CDeleteOrder_1.mqh> 

// Load class
COrderDelete od;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart() 
  {
// Pass external parameters to the class
   od.Init(AllSymbol,BuyStop,SellStop,BuyLimit,SellLimit,BuyStopLimit,SellStopLimit);
// Delete orders
   bool Ret=od.Delete();
// Process result of deleting
   if(Ret) 
     { 
       Alert("Script ended successfully"); 
     }
   else    
     { 
       Alert("Script ended up with error, see details in Journal"); 
     }
  }

Bu komut dosyasının örneğini bu makalenin ekindeki OOP_sDeleteOrders_2.mq5 dosyasında bulabilirsiniz. Komut dosyasının çoğu, Delete() fonksiyonunun sonuçlarını işliyor, böylece komut dosyası sonuçlarını bildiriyor.

Artık komut dosyasının tüm temel fonksiyonları ayrı bir dosyada bulunan bir sınıf olarak tasarlanmıştır, bu nedenle bu sınıfı başka herhangi bir programdan (Uzman Danışman veya Komut Dosyası) kullanabilirsiniz, yani bu komut dosyasını Uzman Danışmandan (EA) çağırabilirsiniz.

 

Biraz Otomatik (Yapıcı ve Yıkıcı)

Programın çalışması üç aşamaya ayrılabilir: programın başlatılması, çalışma süreci ve çalışmanın tamamlanması. Bu ayrımın önemi açıktır: program başladığında kendini hazırlar (örneğin, çalışmak için parametreleri yükler ve ayarlar), program sona erdiğinde bir "temizleme" yapmalıdır (örneğin grafik nesneleri tablodan kaldırmalıdır).

Bu aşamaları ayırmak için Uzman Danışmanların (EA) ve göstergelerin özel fonksiyonları vardır: OnInit() (başlangıçta çalışır) ve OnDeinit() (kapanırken çalışır). Sınıflar benzer özelliklere sahiptir: sınıf yüklendiğinde ve boşaltıldığında otomatik olarak yürütülecek fonksiyonlar ekleyebilirsiniz. Bu fonksiyonlar Yapıcı ve Yıkıcı olarak adlandırılır. Sınıfa bir yapıcı eklemek, sınıf adı olarak tam olarak ada sahip bir fonksiyon eklemek anlamına gelir. Yıkıcı eklemek için - her şeyi yapıcı ile aynı yapın, ancak fonksiyon adı bir tilde "~" ile başlar.

Yapıcı ve yıkıcıyı gösteren bir komut dosyası:

// Class
class CName 
  {
public:
   // Constructor
                     CName() { Alert("Constructor"); }
   // Destructor
                    ~CName() { Alert("Destructor"); }

   void Sleep() { Sleep(3000); }
  };

// Load class
CName cname;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart() 
  {
// Pause
   cname.Sleep();
  }

Bu sınıf aslında 3 saniye duraklayan tek bir Sleep() fonksiyonuna sahiptir. Komut dosyasını çalıştırdığınızda, "Yapıcı" mesajını içeren bir uyarı penceresi görünür, ardından üç saniyelik bir duraklamanın ardından "Yıkıcı" mesajını içeren bir uyarı penceresi görüntülenir. Bu, CName() ve ~CName() fonksiyonlarının hiçbir zaman açıkça çağrılmamasına rağmen geçerlidir.

Bu örneği, bu makalenin ekindeki OOP_sConstDestr_1.mq5 dosyasında bulabilirsiniz.

 

Parametreleri Yapıcıya Geçirme

Komut dosyasını sınıfa dönüştürdüğümüz örnekte, kod miktarını yine de bir satır azaltabilirsiniz - Init() fonksiyonunu çağırmaktan kurtulun. Sınıf yüklenirken parametreler yapıcıya geçirilebilir. Yapıcıyı sınıfa ekleyin:

COrderDelete(bool aAllSymbol     = false,
             bool aBuyStop       = false,
             bool aSellStop      = false,
             bool aBuyLimit      = false,
             bool aSellLimit     = false,
             bool aBuyStopLimit  = false,
             bool aSellStopLimit=false) 
  {
   Init(aAllSymbol,aBuyStop,aSellStop,aBuyLimit,aSellLimit,aBuyStopLimit,aSellStopLimit);
  }

Init() fonksiyonu olduğu gibi kalır, ancak yapıcıdan çağrılır. Yapıcıdaki tüm parametreler isteğe bağlıdır, böylece sınıf daha önce olduğu gibi kullanılabilir: parametresiz sınıfı yükleyin ve Init() fonksiyonunu çağırın.

Bir yapıcı oluşturduktan sonra bu sınıfı kullanmanın başka bir yolu daha vardır. Sınıf yüklendiğinde, Init() fonksiyonunu çağırmanıza gerek kalmadan parametreleri buna geçirebilirsiniz:

COrderDelete od(AllSymbol,BuyStop,SellStop,BuyLimit,SellLimit,BuyStopLimit,SellStopLimit);

Init() fonksiyonu, sınıfın yeniden başlatılmasını sağlamak için herkese açık bölümünde bırakıldı. Programı (Uzman Danışman (EA)) kullandığınızda, bir durumda sadece Durdur emirlerini, diğerinde sadece Limit emirlerini kaldırmanız gerekebilir. Bunu yapmak için Init() fonksiyonunu farklı parametrelerle çağırabilirsiniz, böylece Delete() fonksiyonu farklı bir dizi emri silecektir.

Bu örneği, bu makalenin ekindeki OOP_CDeleteOrder_2.mqh ve OOP_sDeleteOrders_3.mq5 dosyalarında bulabilirsiniz.

 

Bir Sınıfın Çoklu Örneklerini Kullanma

Önceki bölümde bahsedildiği gibi, aynı sınıf, başlatma sırasında ayarlanan parametrelere bağlı olarak farklı eylemler gerçekleştirebilir. Sınıfınızın hangi amaçla kullanılacağını biliyorsanız, sınıfı yeniden başlatmayı atlayabilirsiniz. Bunu yapmak için, farklı parametrelere sahip birkaç sınıf örneği yüklemelisiniz.

Örneğin, EA'mız çalışırken, bazı durumlarda BuyStop ve BuyLimit emirlerini, diğer durumlarda ise - SellStop ve SellLimit emirlerini silmemiz gerektiği bilinmektedir. Bu durumda, sınıfın iki örneğini yükleyebilirsiniz.

BuyStop ve BuyLimit emirlerini silmek için:

COrderDelete DeleteBuy(false,true,false,true,false,false,false);

SellStop ve SellLimit emirlerini silmek için:

COrderDelete DeleteSell(false,false,true,false,true,false,false);

Şimdi, Bekleyen Alış emirlerini silmek istediğinizde, bir sınıfın bir örneğini kullanın:

DeleteBuy.Delete();

Bekleyen Satış emirlerini silmek istediğinizde - başka bir örnek:

DeleteSell.Delete();

 

Nesne Dizisi

Programınız çalışırken kaç tane sınıf örneğine ihtiyacınız olacağını her zaman tam olarak bilemeyebilirsiniz. Bu durumda, bir dizi sınıf örneği (nesne) oluşturabilirsiniz. Yapıcı ve yıkıcıya sahip sınıf örneğinde buna bir göz atalım. Sınıfı biraz değiştirerek, parametreyi yapıcıya geçirelim, böylece sınıfın her bir örneğini izleyebiliriz:

// Class
class CName 
  {
private:
   int               m_arg; // Variable for the instance

public:
   // Constructor
   CName(int aArg) 
     {
      m_arg=aArg;
      Alert("Constructor "+IntegerToString(m_arg));
     }
   // Destructor
  ~CName() 
     { 
      Alert("Destructor "+IntegerToString(m_arg)); 
     }
   //---
   void Sleep() 
     { 
      Sleep(3000); 
     }
  };
Bu sınıfı kullanalım. Belirli bir boyutta bir dizi belirtebilirsiniz, örneğin on öğe:
CName* cname[10];

Her zamanki değişkenler dizisinden bir farkı görün - bir yıldız işareti "*". Yıldız işareti, daha önce kullanılan otomatik işaretçinin aksine dinamik işaretçinin kullanıldığını söyler.

Dinamik bir dizi kullanabilirsiniz (önceden tahsis edilmiş boyut olmadan, dinamik diziyi dinamik işaretçi ile karıştırmayın):

CName* cname[];

Bu durumda, bu ölçeklendirme gerektirecektir (herhangi bir fonksiyonun içinde, komut dosyalarında - OnStart() fonksiyonu içinde gerçekleştirilir):

ArrayResize(cname,10);

Şimdi dizinin tüm öğeleri arasında dolaşalım ve her birine sınıf örneğini yükleyelim. Bunu yapmak için yeni anahtar sözcüğünü kullanın:

ArrayResize(cname,10);
for(int i=0; i<10; i++) 
  {
   cname[i]=new CName(i);
  }
Duraklat:
cname[0].Sleep();

Komut dosyasını kontrol edin. Bunu çalıştırın ve on yapıcı olduğunu, ancak yıkıcı olmadığını görün. Dinamik işaretçiler kullanırsanız, program sonlandırıldığında sınıflar otomatik olarak kaldırılmaz. Buna ek olarak, "Uzmanlar" sekmesinde bellek sızıntıları ile ilgili mesajları görebilirsiniz. Nesneleri manuel olarak silmelisiniz:

for(int i=0; i<10; i++) 
  {
   delete(cname[i]);
  }

Şimdi, komut dosyasının sonunda çalışan on yıkıcı var ve hata mesajı yok.

Bu örneği, bu makalenin ekindeki OOP_sConstDestr_2.mq5 dosyasında bulabilirsiniz.

 

Program Mantığını Değiştirmek için OOP Kullanma (Sanal Fonksiyonlar, Polimorfizm)

Polimorfizm - belki de bu, programınızın mantığını kontrol etmenizi sağlayan en ilginç ve önemli OOP özelliğidir. Sanal fonksiyonlar ve birden çok alt sınıf içeren bir temel sınıftan yararlanır. Bir sınıf, alt sınıflar tarafından tanımlanan çeşitli formlar alabilir.

Basit bir örnek alın - iki değerin karşılaştırılması. Karşılaştırmanın beş versiyonu olabilir: büyüktür (>), küçüktür (<), büyüktür veya eşittir (>=), küçüktür veya eşittir (<=), eşittir (==).

Sanal fonksiyonlu bir temel sınıf oluşturun. Sanal fonksiyon - tam olarak aynı normal fonksiyondur, ancak bildirimi sanal kelimesiyle başlar:

class CCheckVariant 
  {
public:
   virtual bool CheckVariant(int Var1,int Var2) 
     {
      return(false);
     }
  };

Sanal fonksiyonun kodu yoktur. Çeşitli cihazları kabul edecek bir konektör türüdür. Cihazın türüne bağlı olarak farklı eylemler gerçekleştirecektir.

Beş alt sınıf oluşturun:

//+------------------------------------------------------------------+
//|   >                                                              |
//+------------------------------------------------------------------+

class CVariant1: public CCheckVariant
  {
   bool CheckVariant(int Var1,int Var2)
     {
      return(Var1>Var2);
     }
  };
//+------------------------------------------------------------------+
//|   <                                                              |
//+------------------------------------------------------------------+
class CVariant2: public CCheckVariant
  {
   bool CheckVariant(int Var1,int Var2)
     {
      return(Var1<Var2);
     }
  };
//+------------------------------------------------------------------+
//|   >=                                                             |
//+------------------------------------------------------------------+
class CVariant3: public CCheckVariant
  {
   bool CheckVariant(int Var1,int Var2)
     {
      return(Var1>=Var2);
     }
  };
//+------------------------------------------------------------------+
//|   <=                                                             |
//+------------------------------------------------------------------+
class CVariant4: public CCheckVariant
  {
   bool CheckVariant(int Var1,int Var2)
     {
      return(Var1<=Var2);
     }
  };
//+------------------------------------------------------------------+
//|   ==                                                             |
//+------------------------------------------------------------------+
class CVariant5: public CCheckVariant
  {
   bool CheckVariant(int Var1,int Var2)
     {
      return(Var1==Var2);
     }
  };

Bunun, bu sınıfı kullanmadan önce yüklenmesi gerekir. Hangi alt sınıfın kullanılması gerektiğini biliyorsanız, bu alt sınıfın türüyle bir işaretçi bildirebilirsiniz. Örneğin, ">" koşulunu kontrol etmek istiyorsanız:

CVariant1 var; // Load class to check the ">" condition

Bizim durumumuzda olduğu gibi, alt sınıfın türünü önceden bilmiyorsak, temel sınıfın türü ile bir sınıfa yönelik bir işaretçi bildirilir. Ancak bu durumda dinamik işaretçi kullanılır.

CCheckVariant* var;

Bu alt sınıfta yeni anahtar sözcüğü kullanılarak yüklenmelidir. Seçilen varyanta bağlı olarak alt sınıfı yükleyin:

// Number of variant
int Variant=5; 
// Depending on variant number one of five children classes will be used
switch(Variant) 
  {
    case 1: 
       var = new CVariant1;
       break;
    case 2: 
       var = new CVariant2;
       break;
    case 3: 
       var = new CVariant3;
       break;
    case 4: 
       var = new CVariant4;
       break; 
    case 5: 
       var = new CVariant5;
       break; 
 }

Koşulları kontrol edin:

bool rv = var.CheckVariant(1,2);

İki değeri karşılaştırmanın sonucu​koşulları kontrol eden kod tüm durumlar için aynı olsa bile, alt sınıfa bağlı olacaktır.

Bu örneği, bu makalenin ekindeki OOP_sVariant_1.mq5 dosyasında bulabilirsiniz.

 

Kapsülleme Hakkında Daha Fazla Bilgi (özel, korumalı, herkese açık)

Şu an için, bu herkese açık bölüm ile oldukça açıktır - sınıf kullanıcısı tarafından görülmesi gereken fonksiyonları ve değişkenleri içerir (kullanıcı ile hazır bir sınıfı kullanarak programları yazan bir programcıyı kastediyoruz.) Sınıf kullanıcısı açısından, korumalı ve özel bölümler arasında hiçbir fark yoktur - bu bölümlerdeki fonksiyonlar ve değişkenler kullanıcı tarafından kullanılamaz:

//+------------------------------------------------------------------+
//|   Class with the protected keyword                               |
//+------------------------------------------------------------------+
class CName1
  {
protected:
   int ProtectedFunc(int aArg)
     {
      return(aArg);
     }
public:
   int PublicFunction(int aArg)
     {
      return(ProtectedFunc(aArg));
     }
  };
//+------------------------------------------------------------------+
//|   Class with the private keyword                                 |
//+------------------------------------------------------------------+
class CName2
  {
private:
   int PrivateFunc(int aArg)
     {
      return(aArg);
     }
public:
   int PublicFunction(int aArg)
     {
      return(PrivateFunc(aArg));
     }
  };

CName1 c1; // Load class with the protected keyword
CName2 c2; // Load class with the private keyword
Bu örnekte iki sınıf vardır: CName1 ve CName2. Her sınıfın iki fonksiyonu vardır: biri herkese açık bölümde, diğeri korumalı bölümde (CName1 sınıfı için) veya özel bölümde (CName2 sınıfı için) bulunur. Her iki sınıfın da açılır fonksiyon listesindeki herkese açık bölümden yalnızca bir fonksiyonu vardır (Şekiller 2 ve 3).

Şekil 2. CName1 sınıfının fonksiyonları
Şekil 2. CName1 sınıfının fonksiyonları

Şekil 3. CName2 sınıfının fonksiyonları
Şekil 3. CName2 sınıfının fonksiyonları

Bu örneği, bu makalenin ekindeki OOP_sProtPriv_1.mq5 dosyasında bulabilirsiniz.

Özel ve korumalı bölümler, temel sınıf fonksiyonunun alt sınıflarına görünürlüğünü belirler:

//+------------------------------------------------------------------+
//|   Base class                                                     |
//+------------------------------------------------------------------+
class CBase
  {
protected:
   string ProtectedFunc()
     {
      return("CBase ProtectedFunc");
     }
private:
   string PrivateFunc()
     {
      return("CBase PrivateFunc");
     }
public:
   virtual string PublicFunction()
     {
      return("");
     }
  };
//+------------------------------------------------------------------+
//|   Child class                                                    |
//+------------------------------------------------------------------+

class Class: public CBase
  {
public:
   string PublicFunction()
     {
      // With this line everything compiles correctly
      return(ProtectedFunc());
      // If you will uncomment this line and comment the previous one, there will be a compiler error
      // return(PrivateFunc()); 
     }
  };

Bu örnekte, CBase adında temel sınıfımız ve Class adında alt sınıfımız vardır. Alt sınıftan korumalı ve özel bölümlerde bulunan temel sınıf fonksiyonunu çağırmayı deneyin. Korumalı bölümden fonksiyon çağırırsanız her şey derlenir ve çalışır. Özel bölümden fonksiyon çağırırsanız, bir derleyici hatası görüntülenir (özel üye fonksiyonu çağrılamaz). Yani, özel bölümdeki fonksiyon alt sınıflar tarafından görülmez.

Korumalı bölüm fonksiyonları yalnızca sınıf kullanıcılarından korur ve özel bölüm ayrıca fonksiyonları alt sınıflardan korur. Alt sınıflardan temel sınıf fonksiyonlarının (farklı bölümlerde bulunan) görünürlüğü Şekil 4'te gösterilmiştir.

Şekil 4. Alt sınıftan temel sınıf fonksiyonlarının görünürlüğü
Şekil 4. Alt sınıftan temel sınıf fonksiyonlarının görünürlüğü
Mavi oklar - fonksiyonlar mevcuttur, gri - mevcut değildir.

Bu örneği, bu makalenin ekindeki OOP_sProtPriv_2.mq5 dosyasında bulabilirsiniz.

 

Varsayılan Sanal Fonksiyon ve Kalıtım

Temel sınıftaki tüm sanal fonksiyonlar, alt sınıflarda karşılık gelen fonksiyonlara sahip olmak zorunda değildir. Bir alt sınıf aynı ad fonksiyonuna sahipse, bu fonksiyonu kullanacaktır, sahip değilse, temel sınıf sanal fonksiyonundan kodu çalıştıracaktır. Bunu örnek üzerinde düşünün.

//+------------------------------------------------------------------+
//|   Base Class                                                     |
//+------------------------------------------------------------------+
class CBase
  {
public:
   virtual string Function()
     {
      string str="";
      str="Function ";
      str=str+"of base ";
      str=str+"class";
      return(str);
     }
  };
//+------------------------------------------------------------------+
//|   Child class 1                                                  |
//+------------------------------------------------------------------+
class Class1: public CBase
  {
public:
   string Function()
     {
      string str="";
      str="Function ";
      str=str+"of child ";
      return(str);
     }
  };
//+------------------------------------------------------------------+
//|   Child class 2                                                  |
//+------------------------------------------------------------------+
class Class2: public CBase
  {

  };

Class1 c1; // Load class 1
Class2 c2; // Load class 2
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   Alert("1: "+c1.Function()); // Running function from Class1
   Alert("2: "+c2.Function()); // Running function from CBase
  }

Class2 sınıfının hiçbir fonksiyonu olmamasına rağmen, bundan Function() fonksiyonunu çağırmak hala mümkündür. Bu, CBase sınıfından fonksiyonu çalıştıracaktır. Class1 sınıfı kendi fonksiyonunu çalıştıracaktır:

void OnStart() 
   {
    Alert("1: " + c1.Function()); // Running function from Class1
    Alert("2: " + c2.Function()); // Running function from CBase
   }

Sınıf kullanıcısı açısından, bir alt sınıf kullanıldığında, herkese açık bölümdeki temel sınıfın tüm fonksiyonları kullanılabilir olacaktır. Buna kalıtım denir. Temel sınıfın fonksiyonu sanal olarak bildirilirse, bir alt sınıfın bu ada sahip bir fonksiyonu varsa, alt sınıfın fonksiyonu ile değiştirilir (Şekil 5).

Şekil 5. Sınıf Kullanıcıları Tarafından Fonksiyonlara Erişme
Şekil 5. Sınıf Kullanıcıları Tarafından Fonksiyonlara Erişme

Alt sınıfın, temel sınıfın sanal fonksiyonlarına karşılık gelen hiçbir fonksiyonu olmadığı durum dışında, alt sınıfın "ekstra" fonksiyonları olabilir (temel sınıf içinde aynı adı taşıyan sanal fonksiyonları olmayan fonksiyonlar). Sınıfı, alt sınıf türüne işaretçi kullanarak yüklerseniz, bu fonksiyonlar kullanılabilir olacaktır. Sınıfı temel sınıf türüne işaretçi kullanarak yüklerseniz, bu fonksiyonlar kullanılamaz (Şekil 6).

Şekil 6. "Ekstra" Fonksiyonların Görünürlüğü
Şekil 6. "Ekstra" fonksiyonun (kırmızı ok) görünürlüğü
sınıfı yüklemek için kullanılan işaretçi türüne göre belirlenir.

Bu örneği, bu makalenin ekindeki OOP_sDefaultVirtual_1.mq5 dosyasında bulabilirsiniz.

 

Sınıf Yükleme Hakkında Biraz Daha Fazla Bilgi

Sanal fonksiyonları ve buna bağlı olarak temel sınıf ve alt sınıfları kullandığınızda, hangi alt sınıfın kullanılması gerektiğini biliyorsanız, alt sınıfa karşılık gelen bir işaretçi kullanabilirsiniz:

Class1 c1; // Load class 1
Class2 c2; // Load class 2

Hangi alt sınıfın kullanılması gerektiği bilinmiyorsa, temel sınıf türüne dinamik bir işaretçi kullanın ve sınıfı yeni anahtar sözcüğünü kullanarak yükleyin:

CBase *c; // Dynamic pointer 
void OnStart() 
   {
      c=new Class1; // Load class
      ...

Temel sınıfa otomatik işaretçi kullanıyorsanız

CBase c; // Automatic pointer

temel sınıf olduğu gibi kullanılacaktır. Sanal fonksiyonlarını çağırdığınızda bu fonksiyonlar içerisinde yer alan kodu çalıştıracaktır. Sanal fonksiyonlar sıradan fonksiyonlara dönüştürülür.  

 

Fonksiyonda Nesneleri İşleme

Bu bölümün başlığı kendi kendine yeterlidir. Nesnelere işaretçiler fonksiyonlara geçirilebilir ve ardından fonksiyonun içinde nesne fonksiyonlarını çağırabilirsiniz. Fonksiyon parametresi, temel sınıfın türü ile bildirilebilir. Bu, fonksiyonu evrensel kılar. Bir sınıfa yönelik bir işaretçi, yalnızca referans yoluyla fonksiyona geçirilebilir (& işaretiyle gösterilir):

//+------------------------------------------------------------------+
//|   Base Class                                                     |
//+------------------------------------------------------------------+
class CBase
  {
public:
   virtual string Function()
     {
      return("");
     }
  };
//+------------------------------------------------------------------+
//|   Child class 1                                                  |
//+------------------------------------------------------------------+
class Class1: public CBase
  {
public:
   string Function()
     {
      return("Class 1");
     }
  };
//+------------------------------------------------------------------+
//|   Child class 2                                                  |
//+------------------------------------------------------------------+
class Class2: public CBase
  {
public:
   string Function()
     {
      return("Class 2");
     }
  };

Class1 c1; // Load class 1
Class2 c2; // Load class 2
//+------------------------------------------------------------------+
//|   Function to process objects                                    |
//+------------------------------------------------------------------+
void Function(CBase  &c)
  {
   Alert(c.Function());
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
// Process objects using one function.
   Function(c1);
   Function(c2);
  }
Bu örneği, bu makalenin ekindeki OOP_sFunc_1.mq5 dosyasında bulabilirsiniz.

 

Fonksiyonlar ve Yöntemler, Değişkenler ve Özellikler

Buraya kadar bu makalede "fonksiyon" kelimesini kullandık. Ancak OOP'de "fonksiyon" kelimesi yerine programcılar genellikle "yöntem" kelimesini kullanırlar. Sınıfa, bir sınıf yazan bir programcının bakış açısından bakarsanız, tüm fonksiyonlar, fonksiyonlar olarak kalır. Hazır bir sınıf kullanan bir programcının gözünden sınıfa bakarsanız, herkese açık bölümünde (bir nokta yazıldıktan sonra açılır listede bulunur) bulunan sınıf arayüzünün fonksiyonları yöntemler olarak adlandırılır.

Yöntemlere ek olarak, sınıf arayüzü sınıfın özelliklerini içerebilir. Herkese açık bölüm yalnızca fonksiyonları değil aynı zamanda değişkenleri de (diziler dahil) içerebilir.

class CMethodsAndProperties 
   {
    public:
        int               Property1; // Property 1
        int               Property2; // Property 2
        void Function1() 
           {
            //...
            return;
           }
        void Function2() 
           {
            //...
            return;
           }
   };

Bu değişkenler sınıf özellikleri olarak adlandırılacak ve ayrıca açılır listede mevcut olacaktır (Şekil 7).

Şekil 7. Bir listede sınıfın yöntemleri ve özellikleri
Şekil 7. Bir listede sınıfın yöntemleri ve özellikleri

Bu özellikleri değişkenlerle aynı şekilde kullanabilirsiniz:

void OnStart() 
   {
    c.Property1 = 1; // Set property 1
    c.Property2 = 2; // Set property 2

    // Read properties
    Alert("Property1 = " + IntegerToString(c.Property1) + ", Property2 = " + IntegerToString(c.Property2));
   }

Bu örneği, bu makalenin ekindeki OOP_sMethodsAndProperties.mq5 dosyasında bulabilirsiniz.

 

Veri Yapıları

Veri yapıları sınıflara benzer, ancak biraz daha kolaydır. Her ne kadar bu şekilde koyabilseniz de: sınıflar veri yapıları gibidir, ancak daha karmaşıktır. Aradaki fark, veri yapılarının yalnızca değişkenler içerebilmesidir. Bu bakımdan bunları herkese açık, özel ve korumalı bölümler olarak ayırmaya gerek yoktur. Yapının tüm içeriği zaten herkese açık bölümde yer almaktadır. Veri yapısı, değişkenleri bildirdiğiniz parantezlerin içinde yapının adı ile devam eden struct kelimesiyle başlar.

struct Str1 
   {
    int    IntVar;
    int    IntArr[];
    double DblVar[];
    double DblArr[];
   };

Bir yapıyı kullanmak için bir değişken olarak bildirilmelidir, ancak değişken türü yerine yapının adını kullanın.

Str1 s1;

Ayrıca bir dizi yapı bildirebilirsiniz:

Str1 sar1[];

Yapılar yalnızca değişkenleri ve dizileri değil, diğer yapıları da içerebilir:

struct Str2 
   {
    int    IntVar;
    int    IntArr[];
    double DblVar[];
    double DblArr[];
    Str1   Str;
   };

Bu durumda, 2. yapının parçası olan 1. yapıdan değişken çağırmak için iki nokta kullanmanız gerekir:

s2.Str.IntVar=1;

Bu örneği, bu makalenin ekindeki OOP_Struct.mq5 dosyasında bulabilirsiniz.

Sınıflar sadece değişkenleri değil yapıları da içerebilir.

 

Sonuç

Nesne yönelimli programlamanın ana noktalarını ve akılda tutulması gereken önemli anları gözden geçirelim:

1. Sınıf, sınıf anahtar sözcüğü kullanılarak oluşturulur, ardından sınıf adı gelir ve ardından parantezlerin içinde üç bölüm halinde yazılmış sınıfın kodu gelir.

class CName 
  {
private:

protected:

public:
  };

2. Sınıfın fonksiyonları ve değişkenleri üç bölümden birinde bulunabilir: özel, korumalı ve herkese açık. Özel bölümdeki fonksiyonlar ve değişkenler yalnızca sınıf içinde kullanılabilir. Korumalı bölümdeki fonksiyonlar ve değişkenler Sınıf içinde ve alt sınıflar içinde kullanılabilir. Herkese açık bölümdeki fonksiyonlar ve değişkenler herkes için mevcuttur.

3. Sınıf fonksiyonları, sınıfın içinde veya dışında yer alabilir. Fonksiyonları sınıfın dışına yerleştirirseniz, sınıf adını ve her fonksiyon adından önce iki nokta üst üste koyarak hangi sınıfa ait olduklarını belirlemelisiniz:

void ClassName::FunctionName() { ... }

4. Sınıf hem otomatik hem de dinamik işaretçi kullanılarak yüklenebilir. Dinamik işaretçi sınıfı kullanılırken yeni anahtar sözcüğü kullanılarak yüklenmelidir. Bu durumda, programınızı sonlandırırken sil anahtar sözcüğünü kullanarak bir nesneyi silmeniz gerekir.

5. Alt sınıfın temel sınıfa ait olduğunu söylemek için, alt sınıfın adından sonra temel sınıf adını eklemeniz gerekir.

class Class : public CBase { ... }

6. Sınıf başlatma sırasında değerlere sahip değişkenler atayamazsınız. Bu fonksiyonu çalıştırırkendaha sık olarak - yapıcıyı çalıştırırken değerler atayabilirsiniz.

7. Sanal fonksiyonlar, sanal anahtar sözcüğü kullanılarak bildirilir. Alt sınıfın aynı ada sahip bir fonksiyonu varsa, bu fonksiyonu çalıştırır, aksi takdirde, temel sınıfın sanal fonksiyonunu çalıştırır.

8. Sınıflara yönelik işaretçiler, fonksiyonlara geçirilebilir. Fonksiyona herhangi bir alt sınıfa yönelik bir işaretçiyi geçirebilmek için fonksiyon parametrelerini temel sınıf türüyle bildirebilirsiniz.

9. Herkese açık bölümün yalnızca fonksiyonları (yöntemleri) değil, aynı zamanda değişkenleri (özellikleri) vardır.

10. Yapılar dizileri ve diğer yapıları içerebilir.

 

Ekli Dosyaların Listesi

  • OOP_CLibArray_1.mqh - dahil edilen dosya, MQL5/Include klasörüne yerleştirilmelidir. Kitaplık oluşturmak için sınıf kullanma örneği. Korumalı ve özel anahtar sözcükleri. Aşırı yükleme.
  • OOP_CLibArray_2.mqh - dahil edilen dosya, MQL5/Include klasörüne yerleştirilmelidir. Sınıf fonksiyonlarını sınıfın ötesine yerleştirme örneği.
  • OOP_sDeleteOrders_1.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Bekleyen emirleri silmek için basit komut dosyası.
  • OOP_CDeleteOrder_1.mqh - dahil edilen dosya, MQL5/Include klasörüne yerleştirilmelidir. OOP_sDeleteOrders_1 komut dosyasını sınıfa dönüştürme örneği.
  • OOP_sDeleteOrders_2.mq5 - dahil edilen dosya, MQL5/Scripts klasörüne yerleştirilmelidir. Siparişleri silmek için sınıf kullanma örneği. OOP_CDeleteOrder_1.mqh dosyasından alınmıştır (parametreleri Init() fonksiyonu aracılığıyla ayarlama).
  • OOP_sConstDestr_1.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Yapıcı ve yıkıcı demosu.
  • OOP_CDeleteOrder_2.mqh - dahil edilen dosya MQL5/Include klasörüne yerleştirilmelidir. Yapıcı ile emirleri silen ve yapıcı aracılığıyla parametreleri ileten sınıf.
  • OOP_sDeleteOrders_3.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Siparişleri silmek için sınıf kullanma örneği. OOP_CDeleteOrder_2.mqh dosyasından alınmıştır (yapıcı aracılığıyla parametreleri ayarlama).
  • OOP_sConstDestr_2.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Diziye sınıfları yükleme örneği.
  • OOP_sVariant_1.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Alt sınıflara sahip temel sınıf örneği. Sanal fonksiyon, polimorfizm.
  • OOP_sProtPriv_1.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Bir sınıf kullanılırken korumalı ve özel anahtar sözcüklerinin kimliğine bir örnek.
  • OOP_sProtPriv_2.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Alt sınıftaki korumalı ve özel anahtar sözcükleri etkileme örneği.
  • OOP_sDefaultVirtual_1.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Temel sınıfın sanal fonksiyonuna karşılık gelen hiçbir fonksiyonu olmayan alt sınıf örneği.
  • OOP_sFunc_1.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Bir fonksiyonda nesneleri kullanma örneği.
  • OOP_sMethodsAndProperties.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Özelliklerin örneği.
  • OOP_Struct.mq5 - komut dosyası, MQL5/Scripts klasörüne yerleştirilmelidir. Yapıların örnekleri.

Bu dosyaları denedikten sonra, OOP_CDeleteOrder_2.mqh ve OOP_sDeleteOrders_3.mq5 dışında bunların hepsini silebilirsiniz. OOP_CDeleteOrder_2.mqh ve OOP_sDeleteOrders_3.mq5 dosyaları pratik programlamada faydalı olabilir.

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

Ekli dosyalar |
files_en.zip (11.04 KB)
Çok Zaman Dilimli ve Çok Para Birimli Paneller Oluşturmaya Yönelik Nesne Yönelimli Yaklaşım Çok Zaman Dilimli ve Çok Para Birimli Paneller Oluşturmaya Yönelik Nesne Yönelimli Yaklaşım
Bu makale, MetaTrader 5 için çok zaman dilimli ve çok para birimli paneller oluşturmak için nesne yönelimli programlamanın nasıl kullanılabileceğini açıklar. Ana amaç, panelin kodunu değiştirmeye gerek kalmadan fiyatlar, fiyat değişiklikleri, gösterge değerleri veya özel alım/satım koşulları gibi birçok farklı veri türünü görüntülemek için kullanılabilecek evrensel bir panel oluşturmaktır.
MQL5'te Kendi Grafik Panellerinizi Oluşturun MQL5'te Kendi Grafik Panellerinizi Oluşturun
MQL5 programının kullanılabilirliği hem zengin fonksiyonu hem de ayrıntılı bir grafik kullanıcı arayüzü ile belirlenir. Görsel algı bazen hızlı ve istikrarlı çalışmadan daha önemlidir. Standart Kitaplık sınıfları temelinde kendi başınıza ekran panelleri oluşturmanız için adım adım bir kılavuzu aşağıda bulabilirsiniz.
Semafor Göstergelerini Kullanan Basit Alım Satım Sistemleri Semafor Göstergelerini Kullanan Basit Alım Satım Sistemleri
Herhangi bir karmaşık alım satım sistemini dikkatlice incelersek, bunun bir dizi basit alım satım sinyaline dayandığını göreceğiz. Bu nedenle, acemi geliştiricilerin hemen karmaşık algoritmalar yazmaya başlamasına gerek yoktur. Bu makale, sözleşmeleri gerçekleştirmek için semafor göstergelerini kullanan bir alım satım sistemine bir örnek sunmaktadır.
MQL5 Cloud Network ile Hesaplamaları Hızlandırın MQL5 Cloud Network ile Hesaplamaları Hızlandırın
Ana bilgisayarınızda kaç çekirdek var? Bir alım satım stratejisini optimize etmek için kaç bilgisayar kullanabilirsiniz? Burada, bir fare tıklamasıyla dünya çapında bilgi işlem gücünü alarak hesaplamaları hızlandırmak için MQL5 Cloud Network’ün nasıl kullanılacağını gösteriyoruz. "Vakit nakittir" ifadesi her geçen yıl daha da güncel hale geliyor ve önemli hesaplamalar için onlarca saat hatta günlerce beklemeyi göze alamayız.