Discusión sobre el artículo "Usando los punteros de objeto en MQL5" - página 3

 
No utilice punteros en este caso.
 
Barbarian2:

Todavía no entiendo acerca de los punteros y referencias en MQL5 y ahora en MQL4. ¿Cuál es la diferencia entre pasar por referencia y puntero a excepción de código extra? Hay una diferencia en C ++, pero ¿qué es aquí? Si no es difícil de escribir más detallada.

Pasar por referencia requiere que el objeto pasado por referencia sea inicializado. Pasar por puntero no tiene esta restricción:

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);
}

Al llamar a la función TestShapeRef, el código se bloqueará porque la forma no está inicializada. Por otro lado, dentro de la función TestShapePointer, se requieren comprobaciones constantes de si el objeto pasado está inicializado o no. Por lo tanto, siga la regla imprírica:

Si se debe garantizar que el objeto existe en el momento en que se pasa a la función, utilice un pase "&". Si la función requiere un objeto cuyo estado es indefinido - utilice el paso por el puntero "*", y dentro de esta función compruebe la validez del puntero pasado.

Hay otro matiz sutil que debe tener en cuenta. Considere el ejemplo anterior:

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);
}
¿Funcionará correctamente este programa? No, terminará con el error "invalid pointer access" en la línea printf(shape.name); //ERROR (!?) , a pesar de que parece que tenemos garantizada la creación de un objeto en la función TestShapePointer. La cuestión es que en realidad se pasó una referencia NULL en lugar de shape. Es decir, ¡la forma dentro de la función y la forma pasada son objetos diferentes! Por lo tanto, después de salir de la función, shape sigue siendo igual a NULL, y el puntero shape dentro de la función se pierde (se borra en la pila). Por lo tanto.
 

¿Es posible crear un array con objetos de distintos tipos?

Tomemos este ejemplo:

//+------------------------------------------------------------------+
//|#Test.mq5
//| Copyright 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[];
//+------------------------------------------------------------------+
//| Función de inicio del programa de script|
//+------------------------------------------------------------------+
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);
//---
   //objetos[0]. // ¿Cómo acceder a los métodos de la clase CChartObjectEdit?
   //objetos[1]. // ¿Cómo acceder a los métodos de la clase CChartObjectButton?
   //objetos[2]. // ¿Cómo acceder a los métodos de la clase CChartObjectRectLabel?
//---
   while(!IsStopped()) Sleep(1000);
  }
//+------------------------------------------------------------------+
//| Devuelve el número de objetos|
//+------------------------------------------------------------------+
int ElementsTotal()
  {
   return(ArraySize(objects));
  }
//+------------------------------------------------------------------+
//|| Añade un objeto al array|
//+------------------------------------------------------------------+
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()));
  }
//+------------------------------------------------------------------+
//| Traduce el tipo de objeto en una cadena|
//+------------------------------------------------------------------+
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");
  }
//+------------------------------------------------------------------+

//---

¿Cómo acceder a los métodos de las clases heredadas?

 
tol64:

¿Cómo acceder a los métodos de las clases herederas?

¿Has probado a hacer un casting al tipo de destino?
 
Rosh:
¿Has probado a lanzar un tipo de objetivo?
No. Es la primera vez que oigo hablar de ello. ¿Dónde puedo leer sobre ello?
 
tol64:
No. Es la primera vez que oigo hablar de ello. ¿Dónde puedo leer sobre ello?
Es un adjetivo de tipo común, aquí hay un ejemplo:

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CFoo
  {
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CBar : public CFoo
  {
public:
   void func(int x) { Print("Hello from Bar ",x); }
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void func(CFoo *foo)
  {
//--- llamada con casting directamente de puntero a tipo base
   ((CBar*)foo).func(1);
//--- llamada con conversión al tipo de destino y guardando una copia del puntero con el tipo requerido
   CBar *b=(CBar *)foo;
   b.func(2);
//--- borrar la clase creada dinámicamente
   delete foo;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   func(new CBar);
  }
//+------------------------------------------------------------------+
 
mql5:
La conversión de tipo habitual, he aquí un ejemplo:

Gracias. Voy a mirar en él.
 
Rosh:
¿Has probado a hacer un casting al tipo de destino?
Mierda, ¿y hablas de seguridad del lenguaje después de eso?
 
TheXpert:
Mierda, ¿y hablas de seguridad lingüística después de eso?
¿Has encontrado un agujero de seguridad? )
 

¿No sería mejor utilizar el polimorfismo?

Es algo así:

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;