Ponteiros de Objeto

Em MQL5, é possível criar dinamicamente objetos de tipo complexo. Isso é feito usando o operador new, que retorna um identificador para o objeto criado. O descritor tem um tamanho de 8 bytes. Sintaticamente, os descritores de objetos em MQL5 são semelhantes a ponteiros em C++.

Exemplo:

MyObject* hobject= new MyObject();

Ao contrário do C++, a variável hobject do exemplo acima não é um ponteiro para a memória, senão um descritor para um objeto. Além disso, na linguagem MQL5, todos os objetos nos parâmetros da função devem ser passados por referência. Exemplos de passagem de objetos como parâmetro de função:

class Foo
  {
public:
   string            m_name;
   int               m_id;
   static int        s_counter;
   //--- construtores e destruidores
                     Foo(void){Setup("noname");};
                     Foo(string name){Setup(name);};
                    ~Foo(void){};
   //--- inicializamos o objeto Foo
   void              Setup(string name)
     {
      m_name=name;
      s_counter++;
      m_id=s_counter;
     }
  };
int Foo::s_counter=0;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- declaramos o objeto como uma variável com criação automática
   Foo foo1;
//--- variante de passagem de objeto por referência
   PrintObject(foo1);
 
//--- declaramos um ponteiro para um objeto e o criamos usando o operador 'new'
   Foo *foo2=new Foo("foo2");
//--- variante de passagem de um ponteiro para um objeto por referência
   PrintObject(foo2); // o ponteiro para o objeto é convertido automaticamente pelo compilador
 
//--- declaramos um array de objetos Foo
   Foo foo_objects[5];
//--- variante de passagem de array de objetos
   PrintObjectsArray(foo_objects); // função separada para passagem de array de objetos
 
//--- declaramos um array de ponteiros para objetos do tipo Foo
   Foo *foo_pointers[5];
   for(int i=0;i<5;i++)
      foo_pointers[i]=new Foo("foo_pointer");
//--- variante de passagem de array de ponteiros
   PrintPointersArray(foo_pointers); // função separada para passagem de array de ponteiros
 
//--- antes de concluir o trabalho, sempre devemos excluir os objetos criados como ponteiros
   delete(foo2);
//--- removemos o array de ponteiros
   int size=ArraySize(foo_pointers);
   for(int i=0;i<5;i++)
      delete(foo_pointers[i]);
//---   
  }
//+------------------------------------------------------------------+
//| Os objetos são sempre passados por referência                    |
//+------------------------------------------------------------------+
void PrintObject(Foo &object)
  {
   Print(__FUNCTION__,": ",object.m_id," Object name=",object.m_name);
  }
//+------------------------------------------------------------------+
//| Passagem de um array de objetos                                  |
//+------------------------------------------------------------------+
void PrintObjectsArray(Foo &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
//+------------------------------------------------------------------+
//| Passagem de array de ponteiros para um objeto                    |
//+------------------------------------------------------------------+
void PrintPointersArray(Foo* &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
//+------------------------------------------------------------------+

 

Verificação do ponteiro antes de seu uso

A tentativa de acesso a um ponteiro inválido causa o encerramento crítico do programa. Para verificar o ponteiro antes de usá-lo, usamos a função CheckPointer. O ponteiro pode ser inválido quando:

  • o ponteiro é NULL;
  • o objeto foi destruído usando o operador delete.

Esta função pode ser usada como verificação de ponteiro. Um valor diferente de zero garante que os dados possam ser acessados com base nesse ponteiro.

class CMyObject
 {
protected:
  double             m_value;
public:
                     CMyObject(void);
                     CMyObject(double value) {m_value=value;};
                    ~CMyObject(void){};
  //---
  double             Value(void) {return(m_value);}
 };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- criamos um objeto não inicializado
  CMyObject *pointer;
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("1. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- inicializamos o ponteiro
  pointer=new CMyObject(M_PI);
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("2. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- excluimos o objeto
  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
*/

Para verificação rápida do ponteiro, você também pode usar o operador "!" (LNOT) que testa sua validade por meio de uma chamada de função implícita CheckPointer. Isso permite que você escreva o código de forma mais concisa e clara. Veja como seriam as verificações do exemplo anterior:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- criamos um objeto não inicializado
  CMyObject *pointer;
  if(!pointer)
    Print("1. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- inicializamos o ponteiro
  pointer=new CMyObject(M_PI);
  if(!pointer)
    Print("2. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- excluimos o objeto
  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
*/

Para uma verificação rápida de NULL, use o operador "==". Por exemplo: ptr==NULL ou ptr!=NULL.

Também Veja

Variáveis, Inicialização de Variáveis, Visibilidade Escopo e Tempo de Vida de Variáveis, Criando e Excluindo Objetos