"Nesne işaretleyicilerini MQL5'te Kullanma" makalesi için tartışma - sayfa 3

 
Böyle bir durumda işaretçi kullanmayın.
 
Barbarian2:

MQL5'te ve şimdi MQL4'te işaretçiler ve referanslar hakkında hala bir şey anlamıyorum. Ekstra kod dışında referans ve işaretçi ile geçiş arasındaki fark nedir? C++'da bir fark var ama burada ne fark var? Eğer zor değilse daha detaylı yazalım.

Referans ile geçmek, referans ile geçilen nesnenin ilklendirilmesini gerektirir. İşaretçi ile geçişte bu kısıtlama yoktur:

class CShape
{
   public:
      string name;
};

void OnInit()
{
   CShape* shape = NULL; 
   TestShapePointer(shape);
   //Critical Error!
   TestShapeRef(shape);
   
}

void TestShapeRef(CShape& shape)
{
   printf(shape.name);
}

void TestShapePointer(CShape* shape)
{
   if(CheckPointer(shape) != POINTER_INVALID)
      printf(shape.name);
}

TestShapeRef fonksiyonu çağrıldığında, şekil ilklendirilmediği için kod çökecektir. Öte yandan, TestShapePointer fonksiyonu içinde, aktarılan nesnenin ilklendirilip ilklendirilmediğinin sürekli kontrol edilmesi gerekir. Bu nedenle, mantıksız kuralı izleyin:

Nesnenin fonksiyona aktarıldığı anda var olduğu garanti edilmeliyse - bir "&" geçişi kullanın. Eğer fonksiyon durumu tanımlanmamış bir nesne gerektiriyorsa - "*" işaretçisi ile geçişi kullanın ve bu fonksiyonun içinde geçen işaretçinin geçerliliğini kontrol edin.

Aklınızda tutmanız gereken ince bir nüans daha vardır. Önceki örneği düşünün:

class CShape
{
   public:
      string name;
};

void OnInit()
{
   CShape* shape = NULL; 
   TestShapePointer(shape);
   printf(shape.name); //ERROR (!?)
}

void TestShapePointer(CShape* shape)
{
   if(CheckPointer(shape) == POINTER_INVALID)
      shape = new CShape();
   printf(shape.name);
}
Bu program doğru çalışacak mı? Hayır, TestShapePointer fonksiyonunda bir nesne oluşturmayı garantilemiş gibi görünmemize rağmen printf(shape.name); //ERROR (!?) satırında "invalid pointer access" hatası ile sonlanacaktır. Mesele şu ki, aslında shape yerine bir NULL referansı geçildi. Yani, fonksiyonun içindeki şekil ile geçirilen şekil farklı nesnelerdir! Bu nedenle, fonksiyondan çıktıktan sonra, shape hala NULL'a eşittir ve fonksiyon içindeki shape işaretçisi kaybolur (yığında temizlenir). Yani.
 

Farklı türlerde nesneler içeren bir dizi oluşturmak mümkün müdür?

Bu örneği ele alalım:

//+------------------------------------------------------------------+
//|#Test.mq5 |
//| Telif Hakkı 2014, MetaQuotes Software Corp. | |
//|http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//---
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//---
CChartObjectRectLabel rect_label;
CChartObjectButton    button;
CChartObjectEdit      edit;
//---
CChartObject *objects[];
//+------------------------------------------------------------------+
//| Komut dosyası programı başlatma işlevi|
//+------------------------------------------------------------------+
void OnStart()
  {
   edit.Create(0,"edit_1",0,20,20,100,20);
   button.Create(0,"button_1",0,20,40,100,20);
   rect_label.Create(0,"rect_label_1",0,20,60,100,20);
//---
   AddObjectToArray(edit);
   AddObjectToArray(button);
   AddObjectToArray(rect_label);
//---
   //objects[0]. // CChartObjectEdit sınıfının yöntemlerine nasıl erişilir ?
   //objects[1]. // CChartObjectButton sınıfının yöntemlerine nasıl erişilir ?
   //objects[2]. // CChartObjectRectLabel sınıfının yöntemlerine nasıl erişilir ?
//---
   while(!IsStopped()) Sleep(1000);
  }
//+------------------------------------------------------------------+
//| Nesne sayısını döndürür|
//+------------------------------------------------------------------+
int ElementsTotal()
  {
   return(ArraySize(objects));
  }
//+------------------------------------------------------------------+
//|| Diziye bir nesne ekler|
//+------------------------------------------------------------------+
void AddObjectToArray(CChartObject &object)
  {
   int size=ElementsTotal();
//---
   ArrayResize(objects,size+1);
   objects[size]=GetPointer(object);
//---
   if(CheckPointer(objects[size])!=POINTER_INVALID)
      Print(__FUNCSIG__," >>> array["+IntegerToString(size)+"]: ",objects[size].Name(),
            "; object type: ",ObjectTypeToString(objects[size].Type()));
  }
//+------------------------------------------------------------------+
//| Nesne türünü bir dizeye çevirir|
//+------------------------------------------------------------------+
string ObjectTypeToString(int type)
  {
   string str="";
//---
   switch((ENUM_OBJECT)type)
     {
      case OBJ_EDIT            : return("edit");            break;
      case OBJ_BUTTON          : return("button");          break;
      case OBJ_RECTANGLE_LABEL : return("rectangle label"); break;
     }
//---
   return("undefined object type");
  }
//+------------------------------------------------------------------+

//---

Miras alınan sınıfların yöntemlerine nasıl erişilir?

 
tol64:

Mirasçı sınıfların yöntemlerine nasıl erişilir?

Hedef türe döküm yapmayı denediniz mi?
 
Rosh:
Bir hedef türü seçmeyi denediniz mi?
Hayır. İlk defa duyuyorum. Nerede okuyabilirim?
 
tol64:
Hayır. İlk defa duyuyorum. Nerede okuyabilirim?
Yaygın bir sıfat türüdür, işte bir örnek:

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CFoo
  {
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CBar : public CFoo
  {
public:
   void func(int x) { Print("Hello from Bar ",x); }
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void func(CFoo *foo)
  {
//--- doğrudan işaretçiden temel türe döküm ile çağrı
   ((CBar*)foo).func(1);
//--- hedef türe dönüştürme ve işaretçinin bir kopyasını gerekli türle kaydetme ile çağrı
   CBar *b=(CBar *)foo;
   b.func(2);
//--- dinamik olarak oluşturulan sınıfı sil
   delete foo;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   func(new CBar);
  }
//+------------------------------------------------------------------+
 
mql5:
Olağan tip dönüşümü, işte bir örnek:

Teşekkür ederim. Bununla ilgileneceğim.
 
Rosh:
Hedef türe döküm yapmayı denediniz mi?
Kahretsin, ve ondan sonra dil güvenliğinden mi bahsediyorsun?
 
TheXpert:
Kahretsin, bundan sonra dil güvenliğinden mi bahsediyorsun?
Bir güvenlik açığı mı buldunuz? )
 

Çok biçimlilik kullanmak daha iyi olmaz mıydı?

Şöyle bir şey:

CChartObject *ptr_rect_label;
CChartObject *ptr_button;
CChartObject *ptr_edit;
CChartObject *objects[];
//---
ptr_rect_label=new CChartObjectRectLabel;
ptr_button=new CChartObjectButton;
ptr_edit=new CChartObjectEdit;