Punteros a objetos

En MQL5, es posible crear dinámicamente objetos de tipo complejo. Esto se hace usando el operador new,que retorna el descriptor del objeto creado. El descriptor tiene un tamaño de 8 bytes. Sintácticamente, los descriptores de los objetos en MQL5 son similares a los punteros en C++.

Ejemplo:

MyObject* hobject= new MyObject();

A diferencia de C++, la variable hobject en el ejemplo anterior no es un puntero de memoria, sino un descriptor de objeto. Además, en MQL5, todos los objetos de los parámetros de las funciones deben transmitirse por referencia. Ejemplos de transmisión de objetos como parámetros de funciones:

class Foo
  {
public::
   string            m_name;
   int               m_id;
   static int        s_counter;
   //--- constructores y destructores
                     Foo(void){Setup("noname");};
                     Foo(string name){Setup(name);};
                    ~Foo(void){};
   //--- inicializamos el 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 el objeto como una variable con creación automática
   Foo foo1;
//--- variante de transmisión de un objeto por referencia
   PrintObject(foo1);
 
//--- declaramos un puntero a un objeto y lo creamos con el operador 'new'
   Foo *foo2=new Foo("foo2");
//--- variante de transmisión de un puntero a un objeto por referencia
   PrintObject(foo2); // el puntero a un objeto es convertido automáticamente por el compilador
 
//--- declaramos un array de objetos Foo
   Foo foo_objects[5];
//--- variante de transmisión de un array de objetos
   PrintObjectsArray(foo_objects); // función separada para pasar un array de objetos
 
//--- declaramos un array de punteros a los objetos Foo
   Foo *foo_pointers[5];
   for(int i=0;i<5;i++)
      foo_pointers[i]=new Foo("foo_pointer");
//--- variante de transmisión de un array de objetos
   PrintPointersArray(foo_pointers); // función aparte para transmitir un array de objetos
 
//--- antes de completar el trabajo, nos aseguramos de borrar los objetos creados como punteros
   delete(foo2);
//--- borramos el array de punteros
   int size=ArraySize(foo_pointers);
   for(int i=0;i<5;i++)
      delete(foo_pointers[i]);
//---   
  }
//+------------------------------------------------------------------+
//| Los objetos siempre se transmiten por referencia |
//+------------------------------------------------------------------+
void PrintObject(Foo &object)
  {
   Print(__FUNCTION__,": ",object.m_id," Object name=",object.m_name);
  }
//+------------------------------------------------------------------+
//| Transmisión de un array de objetos |
//+------------------------------------------------------------------+
void PrintObjectsArray(Foo &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
//+------------------------------------------------------------------+
//| Transmisión de un array de punteros de objeto                     |
//+------------------------------------------------------------------+
void PrintPointersArray(Foo* &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
//+------------------------------------------------------------------+

 

Comprobación del puntero antes de su uso

El intenta de acceso a un puntero no válido provoca la finalización crítica del programa. Para comprobar un puntero antes de usarlo, utilice la función CheckPointer. El puntero puede no ser válido en los siguientes casos:

  • el puntero es igual a NULL;
  • el objeto ha sido destruido por el operador delete.

Esta función se puede usar como comprobación de la corrección de un puntero. Un valor distinto a cero asegura que se pueda acceder a los datos usando este puntero.

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()
 {
//--- creamos un objeto no inicializado
  CMyObject *pointer;
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("1. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- inicializamos el puntero
  pointer=new CMyObject(M_PI);
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("2. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- eliminamos el 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
*/

También podemos usar el operador "!" ( para comprobar rápidamente el punteroLNOT), que comprueba su validez usando una llamada implícita a la función CheckPointer. Esto nos permite escribir el código de forma más concisa y clara. Este es el aspecto que tendrían las comprobaciones del ejemplo anterior:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- creamos un objeto no inicializado
  CMyObject *pointer;
  if(!pointer)
    Print("1. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- inicializamos el puntero
  pointer=new CMyObject(M_PI);
  if(!pointer)
    Print("2. pointer is "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- eliminamos el 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 comprobar rápidamente la existencia de NULL, usamos el operador "==". Por ejemplo: ptr==NULL o ptr!=NULL.

Véase también

Variables, Inicialización de variables, Visibilidad y tiempo de vida de variables, Creación y eliminación de objetos