Puntatori agli Oggetti

MQL5 consente la creazione dinamica di oggetti di tipo complesso. Questo viene fatto utilizzando l'operatore 'new' che restituisce un descrittore dell'oggetto creato. La dimensione del descrittore è 8 byte. Sintatticamente, i descrittori di oggetti in MQL5 sono simili ai puntatori C++.

Esempio:

MyObject* hobject= new MyObject();

A differenza di C++, la variabile "hobject" dell'esempio sopra non è un puntatore alla memoria, ma è un descrittore di oggetti. Inoltre, in MQL5, tutti gli oggetti nei parametri della funzione devono essere passati per riferimento. Gli esempi seguenti mostrano il passaggio di oggetti come parametri di funzione:

class Foo
  {
public:
   string            m_name;
   int               m_id;
   static int        s_counter;
 //--- costruttori e distruttori
                     Foo(void){Setup("noname");};
                     Foo(string name){Setup(name);};
                    ~Foo(void){};
 //--- inizializzo l'oggetto Foo
   void              Setup(string name)
     {
      m_name=name;
      s_counter++;
      m_id=s_counter;
     }
  };
int Foo::s_counter=0;
//+------------------------------------------------------------------+
//| Funzione start del programma script                              |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- dichiaro l'oggetto come una variabile, con creazione automatica
   Foo foo1;
//--- variante del passaggio di un oggetto per riferimento
   PrintObject(foo1);
 
//--- dichiaro un puntatore a un oggetto e lo creo usando l'operatore 'new'
   Foo *foo2=new Foo("foo2");
//--- variante del passaggio di un puntatore ad un oggetto per riferimento
   PrintObject(foo2); // il puntatore all'oggetto viene convertito automaticamente dal compilatore
 
//--- dichiaro un array di oggetti Foo
   Foo foo_objects[5];
//--- variante del passaggio di un array di oggetti
   PrintObjectsArray(foo_objects); // una funzione separata per passare un array di oggetti
 
//--- dichiaro un array di puntatori a oggetti di tipo Foo
   Foo *foo_pointers[5];
   for(int i=0;i<5;i++)
      foo_pointers[i]=new Foo("foo_pointer");
//--- variante del passaggio di un array di puntatori
   PrintPointersArray(foo_pointers); // una funzione separata per passare un array di puntatori
 
//--- prima di finire, assicurati di eliminare gli oggetti creati come puntatori
   delete(foo2);
//--- rimuovi l'array di puntatori
   int size=ArraySize(foo_pointers);
   for(int i=0;i<5;i++)
      delete(foo_pointers[i]);
//---   
  }
//+------------------------------------------------------------------+
// Gli oggetti sono passati sempre per riferimento                   |
//+------------------------------------------------------------------+
void PrintObject(Foo &object)
  {
   Print(__FUNCTION__,": ",object.m_id," Object name=",object.m_name);
  }
//+------------------------------------------------------------------+
// Passaggio di un array di oggetti                                  |
//+------------------------------------------------------------------+
void PrintObjectsArray(Foo &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
//+------------------------------------------------------------------+
// Passaggio di un array di puntatori di oggetti                     |
//+------------------------------------------------------------------+
void PrintPointersArray(Foo* &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
//+------------------------------------------------------------------+

 

Controllare il puntatore prima dell'uso

Un tentativo di accedere a un puntatore non valido provoca l'arresto critico del programma. La funzioneCheckPointer viene utilizzata per controllare un puntatore prima dell'uso. Il puntatore può non essere valido nei seguenti casi:

  • il puntatore è uguale a NULL;
  • l'oggetto è stato distrutto utilizzando l'operatore delete.

Questa funzione può essere utilizzata per convalidare un puntatore. Un valore diverso da zero indica che è possibile accedere ai dati su questo puntatore.

class CMyObject
 {
protected:
  double             m_value;
public:
                     CMyObject(void);
                     CMyObject(double value) {m_value=value;};
                    ~CMyObject(void){};
  //---
  double             Value(void) {return(m_value);}
 };
//+------------------------------------------------------------------+
//| Funzione start del programma script                              |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- creo un oggetto non inizializzato
  CMyObject *pointer;
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("1. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- inizializzo il puntatore
  pointer=new CMyObject(M_PI);
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("2. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- elimino l'oggetto
  delete(pointer);
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("3. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("3. pointer.Value()="pointer.Value());
 }
/*
   1pointer is POINTER_INVALID
   2pointer.Value()=3.141592653589793
   3pointer is POINTER_INVALID
*/

Per convalidare rapidamente il puntatore, puoi anche utilizzare l'operatore "!" (LNOT) che lo verifica tramite una chiamata implicita della funzione CheckPointer. Ciò consente una scrittura del codice più concisa e chiara. Di seguito sono riportati i controlli dell'esempio precedente:

//+------------------------------------------------------------------+
//| Funzione start del programma script                              |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- creo un oggetto non inizializzato
  CMyObject *pointer;
  if(!pointer)
    Print("1. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- inizializzo il puntatore
  pointer=new CMyObject(M_PI);
  if(!pointer)
    Print("2. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- elimino l'oggetto
  delete(pointer);
  if(!pointer)
    Print("3. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("3. pointer.Value()="pointer.Value());
 }
/*
   1pointer is POINTER_INVALID
   2pointer.Value()=3.141592653589793
   3pointer is POINTER_INVALID
*/

L'operatore "==" viene utilizzato per un rapido controllo di NULL. Per esempio: ptr==NULL or ptr!=NULL.

Vedi anche

Variabili, Inizializzazione delle Variabili, Visibilità Campo e Durata delle Variabili, Creazione ed Eliminazione di Oggetti