Discussão do artigo "Usando os Ponteiros de Objeto no MQL5" - página 3

 
Nesse caso, não use ponteiros.
 
Barbarian2:

Ainda não entendi o que são ponteiros e referências na MQL5 e agora na MQL4. Qual é a diferença entre passar por referência e ponteiro, exceto pelo código extra? Existe uma diferença no C++, mas qual é a diferença aqui? Se não for difícil escrever mais detalhadamente.

A passagem por referência exige que o objeto passado por referência seja inicializado. A passagem por ponteiro não tem essa restrição:

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

Ao chamar a função TestShapeRef, o código falhará porque a forma não está inicializada. Por outro lado, dentro da função TestShapePointer, são necessárias verificações constantes se o objeto passado está inicializado ou não. Portanto, siga a regra do imprimário:

Se for necessário garantir a existência do objeto no momento em que ele for passado para a função, use uma passagem "&". Se a função exigir um objeto cujo estado seja indefinido, use a passagem pelo ponteiro "*" e, dentro dessa função, verifique a validade do ponteiro passado.

Há mais uma nuance sutil que você deve ter em mente. Considere o exemplo 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);
}
Esse programa funcionará corretamente? Não, ele terminará com o erro "acesso a ponteiro inválido" na linha printf(shape.name); //ERROR (!?) , apesar do fato de que parece que temos a garantia de criar um objeto na função TestShapePointer. A questão é que, de fato, uma referência NULL foi passada em vez de shape. Ou seja, a forma dentro da função e a forma passada são objetos diferentes! Assim, depois de sair da função, shape ainda é igual a NULL e o ponteiro de shape dentro da função é perdido (limpo na pilha). Portanto.
 

É possível criar uma matriz com objetos de tipos diferentes?

Vejamos este exemplo:

//+------------------------------------------------------------------+
//|#Teste.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[];
//+------------------------------------------------------------------+
//| Função de início do 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]. // Como obter acesso aos métodos da classe CChartObjectEdit?
   //objetos[1]. // Como obter acesso aos métodos da classe CChartObjectButton?
   //objetos[2]. // Como obter acesso aos métodos da classe CChartObjectRectLabel?
//---
   while(!IsStopped()) Sleep(1000);
  }
//+------------------------------------------------------------------+
//| Retorna o número de objetos|
//+------------------------------------------------------------------+
int ElementsTotal()
  {
   return(ArraySize(objects));
  }
//+------------------------------------------------------------------+
//|| Adiciona um objeto à matriz|
//+------------------------------------------------------------------+
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()));
  }
//+------------------------------------------------------------------+
//| Traduz o tipo de objeto em uma string|
//+------------------------------------------------------------------+
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");
  }
//+------------------------------------------------------------------+

//---

Como obter acesso a métodos de classes herdadas?

 
tol64:

Como acessar métodos de classes herdadas?

Você já tentou fazer o casting para o tipo de destino?
 
Rosh:
Você já tentou lançar um tipo de alvo?
Não. É a primeira vez que ouço falar disso. Onde posso ler sobre isso?
 
tol64:
Não. Esta é a primeira vez que ouço falar disso. Onde posso ler sobre isso?
É um tipo de adjetivo comum, aqui está um exemplo:

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CFoo
  {
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CBar : public CFoo
  {
public:
   void func(int x) { Print("Hello from Bar ",x); }
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void func(CFoo *foo)
  {
//--- chamada com conversão diretamente do ponteiro para o tipo de base
   ((CBar*)foo).func(1);
//--- chamada com conversão para o tipo de destino e salvando uma cópia do ponteiro com o tipo necessário
   CBar *b=(CBar *)foo;
   b.func(2);
//--- excluir a classe criada dinamicamente
   delete foo;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   func(new CBar);
  }
//+------------------------------------------------------------------+
 
mql5:
A conversão de tipo usual, aqui está um exemplo:

Obrigado. Vou dar uma olhada nisso.
 
Rosh:
Você já tentou fazer o casting para o tipo de destino?
Droga, e você fala sobre segurança de linguagem depois disso?
 
TheXpert:
Droga, e você está falando sobre segurança de linguagem depois disso?
Você encontrou uma falha de segurança? )
 

Não seria melhor usar o polimorfismo?

É mais ou menos assim:

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;