PLO. Application issues - page 8

 
Interesting:

1. The descendant functionality is not available. I don't know who or how, but personally I never got access to SetRadius() and SetSide() from the Array.Maybe there's a way to solve the problem with autogenous, but I want to do without it.

2. Maybe I'm working incorrectly with pointers, but I either have a leak all the time or have to hit the pointers right in the block where the main work is done.

All available... my post above
 
equivalent23:

Can I give you an example?

It's just that the example I gave was taken from the documentation and it's not clear how it should work...

This is how it works. But completely out of documentation :/ (But once again I've practiced on pointers)

#property copyright "Ya"
#property link      "Ya"
#property version   "1.00"
//--- Базовый класс
class CShape
  {
protected:
   int               m_type;                // тип фигуры
   int               m_xpos;                // X - координата точки привязки
   int               m_ypos;                // Y - координата точки привязки
public:
   void           CShape(){m_type=0;};   // конструктор, тип равен нулю
   int            GetType(){return(m_type);};// возвращает тип фигуры
   virtual void           SetRadius(double r){return;};
   virtual void           SetSide(double s){return;};
   virtual double         GetArea(){return(0); }// возвращает площадь фигуры
  };
//--- производный класс Круг
class CCircle: public CShape          // после двоеточия указывается базовый класс,
  {                                      // от которого производится наследование 
private:
   double            m_radius;              // радиус круга

public:
   void           CCircle(){m_type=1; m_radius=10;};  // конструктор, тип равен 1 
   virtual void           SetRadius(double r){m_radius=r;};
   virtual double GetArea(){return(3.14*m_radius*m_radius);}// площадь круга
  };
//--- производный класс Квадрат
class CSquare: public CShape          // после двоеточия указывается базовый класс,
  {                                      // от которого производится наследование 
private:
   double            m_square_side;        // сторона квадрата

public:
   void            CSquare(){m_type=2;}; // конструктор, тип равен 2 
   virtual void            SetSide(double s){m_square_side=s;};
   virtual double GetArea(){return(m_square_side*m_square_side);}//площадь квадрата
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   CCircle *ci=new CCircle;
   CSquare *sq=new CSquare;
   CShape  *shapes[2];                       // массив объектов CShape

   shapes[0]=ci;
   shapes[1]=sq;
////---зададим уникальные свойства объектов
   shapes[0].SetRadius(5.0);
   shapes[1].SetSide(4.0);
   for(int i=0; i<2;i++)
     {
      //--- тип и площадь фигуры
      Print("Объект типа "+shapes[i].GetType()+" имеет площадь "+shapes[i].GetArea());
     }
 
AlexSTAL:

Execute:

can be done much more simply... virtualization:


That's not what I'm talking about. We're not talking about just using pointers, we're talking about an array of these pointers with a base class type.

CShape ArrShapes[10]; // массив объектов CShape

It doesn't matter whether it's a simple array or an array of pointers, only what's written in the base class works and is available.

Or maybe I'm missing something.

For example, a slightly modified base class (designed as a structure)

//class CShape
struct CShape
//Базовый класс
{  
protected: 
int            m_type;                // тип фигуры
int            m_xpos;                // X - координата точки привязки
int            m_ypos;                // Y - координата точки привязки

public:
void           CShape(){m_type=0;};   // конструктор, тип равен нулю
int            GetType(){return(m_type);};// возвращает тип фигуры

void           SetPosX(int s){m_xpos=s;};
int            GetPosX(){return(m_xpos);};

void           SetPosY(int s){m_ypos=s;};
int            GetPosY(){return(m_ypos);};

double GetArea(){return (0); }// возвращает площадь фигуры

};

If we cram all this stuff into the array, we'll get access to at least functionality declared in the base class.

The question is how to access functionality by descendant if the array is of base class type (i.e. array is of CShape type)?

Когда нужно использовать указатели в MQL5
Когда нужно использовать указатели в MQL5
  • 2010.03.25
  • MetaQuotes Software Corp.
  • www.mql5.com
Все объекты в MQL5 по умолчанию передаются по ссылке, но есть возможность использовать и указатели объектов. При этом есть опасность получить в качестве параметра функции указатель неинициализированного объекта. В этом случае работа программы будет завершена критически с последующей выгрузкой. Автоматически создаваемые объекты как правило такой ошибки не вызывают, и в этом отношении они достаточно безопасны. В этой статье мы попробуем разобраться в чем разница между ссылкой и указателей, когда оправдано использование указателей и как написать безопасный код с использованием указателей.
 
Interesting:

that's not what I'm talking about. We're not talking about simply using pointers, but about an array of these pointers with a base class type.

The question is how to access the functionality by a descendant if the array is of base class type (i.e. the array is of CShape type)?

I wrote on the last page how:

class CBase
  {
public:
   void m_radius() {Print("CBase");}
  };

class CTest : public CBase
  {
public:
   void m_radius() {Print("CTest");}
  };

CBase* Base;

void OnStart()
  {
   Base = new CTest;
   Base.m_radius();
   ((CTest *)Base).m_radius();
   delete Base;
  }
 

Same code, only with an array:

class CBase
  {
public:
   void m_radius() {Print("CBase");}
  };

class CTest : public CBase
  {
public:
   void m_radius() {Print("CTest");}
  };

CBase* Base[1];

void OnStart()
  {
   Base[0] = new CTest;
   Base[0].m_radius();
   ((CTest *)Base[0]).m_radius();
   delete Base[0];
  }
 
Yedelkin:

That's how it works. But completely off the documentation :/

Well, I mean the same thing, you should at least designate all functions in a base class (otherwise they won't be accessible).
 
AlexSTAL:

Execute:

For something like this:

((CTest *)Base).m_radius();

should be ripped off with the confiscation of the keyboard.

In C++ you can move through class hierarchy with dynamic_cast, and it is not liked there either. In MQL, it can cause implicit crashes that cannot be easily solved, because the bug is in a completely different place.

Therefore, I strongly advise against using this type of conversion. That is, at all. To ancestors please, to children ni.

 
TheXpert:

For something like this:

You should take your hands off and have your keyboard confiscated.

In C++, you can move through class hierarchy using dynamic_cast, and it is not liked there either. In MQL it can cause implicit crashes that cannot be easily solved, because the bug is in a completely different place.

Therefore, I categorically advise against using such a conversion. That is, not at all. To ancestors please, not to children.

What's the polite way to answer....

If the programmer is too dumb, then a simple 1+1 operation can cause implicit crashes....

And I want to point out that MQL5 is not C++...

This is just a possibility, not a question of application....

 
AlexSTAL:

Same code, only with an array:


1. Remove m_radius() from the ancestor, it's not in the example. :) And you will get no work with it in OnStart();

2. can the delete Base[0] line be moved somewhere else? Say, if it's not a script but an owl and I still need the data in the array.

I got memory leaks right away. I had to switch to structures for this reason...

 
Interesting:

1. Remove m_radius(), it is not present in the example. And get no work with it in OnStart();

2. may I move delete Base[0] line somewhere else? Say, if it's not a script but an owl, and I still need the data in the array.

I got a memory leak right away. I had to switch to structures for this reason...

1) Removed, it works:

class CBase
  {
public:
  };

class CTest : public CBase
  {
public:
   void m_radius() {Print("CTest");}
  };

CBase* Base[1];

void OnStart()
  {
   Base[0] = new CTest;
   ((CTest *)Base[0]).m_radius();
   delete Base[0];
  }
2) The main thing is to delete it before the program ends... But if you have this pointer created in a function, you need to take care of saving it in a global location...
Reason: