Discussione sull’articolo "Usare i Puntatori di Oggetti in MQL5" - pagina 3

 
In questo caso non si devono usare i puntatori.
 
Barbarian2:

Non riesco ancora a capire i puntatori e i riferimenti in MQL5 e ora in MQL4. Qual è la differenza tra passaggio per riferimento e puntatore, a parte il codice extra? C'è una differenza in C++, ma qual è qui? Se non è difficile scrivere in modo più dettagliato.

Il passaggio per riferimento richiede che l'oggetto passato per riferimento sia inizializzato. Il passaggio per puntatore non ha questa restrizione:

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

Quando si chiama la funzione TestShapeRef, il codice si blocca perché la forma non è inizializzata. D'altra parte, all'interno della funzione TestShapePointer, sono necessari controlli costanti per verificare se l'oggetto passato è inizializzato o meno. Pertanto, si deve seguire la regola dell'imprimatur:

Se l'oggetto deve essere garantito come esistente nel momento in cui viene passato alla funzione, utilizzare un passaggio "&". Se la funzione richiede un oggetto il cui stato è indefinito, utilizzare il passaggio con il puntatore "*" e all'interno di questa funzione controllare la validità del puntatore passato.

C'è un'altra sottile sfumatura da tenere a mente. Considerate l'esempio precedente:

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);
}
Questo programma funzionerà correttamente? No, terminerà con l'errore "accesso al puntatore non valido" alla riga printf(shape.name); //ERRORE (!?) , nonostante il fatto che sembra garantita la creazione di un oggetto nella funzione TestShapePointer. Il punto è che in realtà è stato passato un riferimento NULL al posto della forma. Cioè, la forma all'interno della funzione e quella passata sono oggetti diversi! Pertanto, dopo l'uscita dalla funzione, shape è ancora uguale a NULL e il puntatore a shape all'interno della funzione è perso (cancellato nello stack). Quindi.
 

È possibile creare un array con oggetti di tipo diverso?

Prendiamo questo esempio:

//+------------------------------------------------------------------+
//|#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[];
//+------------------------------------------------------------------+
//| Funzione di avvio del programma di 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);
//---
   //oggetti[0]. // Come ottenere l'accesso ai metodi della classe CChartObjectEdit?
   //oggetti[1]. // Come ottenere l'accesso ai metodi della classe CChartObjectButton?
   //oggetti[2]. // Come accedere ai metodi della classe CChartObjectRectLabel?
//---
   while(!IsStopped()) Sleep(1000);
  }
//+------------------------------------------------------------------+
//| Restituisce il numero di oggetti|
//+------------------------------------------------------------------+
int ElementsTotal()
  {
   return(ArraySize(objects));
  }
//+------------------------------------------------------------------+
//| Aggiunge un oggetto all'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 il tipo di oggetto in una stringa|
//+------------------------------------------------------------------+
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");
  }
//+------------------------------------------------------------------+

//---

Come ottenere l'accesso ai metodi delle classi ereditate?

 
tol64:

Come accedere ai metodi delle classi ereditarie?

Si è provato a eseguire il casting sul tipo di destinazione?
 
Rosh:
Hai provato a lanciare un tipo di bersaglio?
No. È la prima volta che ne sento parlare. Dove posso leggere qualcosa al riguardo?
 
tol64:
No. È la prima volta che ne sento parlare. Dove posso leggere qualcosa al riguardo?
È un aggettivo di tipo comune, ecco un esempio:

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CFoo
  {
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CBar : public CFoo
  {
public:
   void func(int x) { Print("Hello from Bar ",x); }
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void func(CFoo *foo)
  {
//--- chiamata con casting direttamente dal puntatore al tipo base
   ((CBar*)foo).func(1);
//--- chiamata con conversione al tipo di destinazione e salvataggio di una copia del puntatore con il tipo richiesto
   CBar *b=(CBar *)foo;
   b.func(2);
//--- eliminare la classe creata dinamicamente
   delete foo;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   func(new CBar);
  }
//+------------------------------------------------------------------+
 
mql5:
La solita conversione di tipo, ecco un esempio:

Grazie. Ci darò un'occhiata.
 
Rosh:
Hai provato a fare il casting sul tipo di destinazione?
Merda, e poi parli di sicurezza del linguaggio?
 
TheXpert:
Merda, e dopo parli di sicurezza del linguaggio?
Hai trovato una falla nella sicurezza? )
 

Non sarebbe meglio usare il polimorfismo?

Funziona più o meno così:

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;