Discussion of article "Using the Object Pointers in MQL5" - page 3

 
Do not use pointers in such a case.
 
Barbarian2:

I still don't understand about pointers and references in MQL5 and now in MQL4. What is the difference between passing by reference and pointer except for extra code? There is a difference in C++, but what is it here? If it is not difficult to write more detailed.

Passing by reference requires that the object passed by reference be initialised. Passing by pointer does not have this restriction:

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

When calling the TestShapeRef function, the code will crash because the shape is not initialised. On the other hand, inside the TestShapePointer function, constant checks are required whether the passed object is initialised or not. Therefore, follow the imprirical rule:

If the object must be guaranteed to exist at the time it is passed to the function - use a "&" pass. If the function requires an object whose state is undefined - use passing by the "*" pointer, and inside this function check the validity of the passed pointer.

There is one more subtle nuance you should keep in mind. Consider the previous example:

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);
}
Will this program work correctly? No, it will end with the error "invalid pointer access" at the line printf(shape.name); //ERROR (!?) , despite the fact that we seem to be guaranteed to create an object in the TestShapePointer function. The point is that in fact a NULL reference was passed instead of shape. That is, the shape inside the function and the passed shape are different objects! Thus, after exiting the function, shape is still equal to NULL, and the shape pointer inside the function is lost (cleared in the stack). So.
 

Is it possible to create an array with objects of different types?

Let's take this example:

//+------------------------------------------------------------------+
//|#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[];
//+------------------------------------------------------------------+
//| Script programme start function|
//+------------------------------------------------------------------+
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);
//---
   //objects[0]. // How to get access to methods of CChartObjectEdit class ?
   //objects[1]. // How to get access to methods of CChartObjectButton class ?
   //objects[2]. // How to get access to methods of CChartObjectRectLabel class ?
//---
   while(!IsStopped()) Sleep(1000);
  }
//+------------------------------------------------------------------+
//| Returns the number of objects|
//+------------------------------------------------------------------+
int ElementsTotal()
  {
   return(ArraySize(objects));
  }
//+------------------------------------------------------------------+
//|| Adds an object to the 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()));
  }
//+------------------------------------------------------------------+
//| Translates the object type into a 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");
  }
//+------------------------------------------------------------------+

//---

How to get access to methods of inherited classes?

 
tol64:

How to access methods of inheritor classes?

Have you tried casting to the target type?
 
Rosh:
Have you tried casting a target type?
No. First time I've heard of it. Where can I read about it?
 
tol64:
No. This is the first I've heard of it. Where can I read about it?
It's a common type adjective, here's an example:

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CFoo
  {
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CBar : public CFoo
  {
public:
   void func(int x) { Print("Hello from Bar ",x); }
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void func(CFoo *foo)
  {
//--- call with casting directly from pointer to base type
   ((CBar*)foo).func(1);
//--- call with conversion to the target type and saving a copy of the pointer with the required type
   CBar *b=(CBar *)foo;
   b.func(2);
//--- delete the dynamically created class
   delete foo;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   func(new CBar);
  }
//+------------------------------------------------------------------+
 
mql5:
The usual type conversion, here's an example:

Thank you. I'll look into it.
 
Rosh:
Have you tried casting to the target type?
Shit, and after that you talk about language safety?
 
TheXpert:
Shit, and you're talking about language security after that?
Did you find a security hole? )
 

Wouldn't it be better to use polymorphism?

It goes something like this:

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;