OLP. Problèmes d'application - page 8

 
Interesting:

1. La fonctionnalité descendante n'est pas disponible. Je ne sais pas qui ou comment, mais personnellement je n'ai jamais eu accès à SetRadius() et SetSide() à partir de l'Array.Peut-être y a-t-il un moyen de résoudre le problème avec autogenous, mais je veux m'en passer.

2. Peut-être que je ne travaille pas correctement avec les pointeurs, mais soit j'ai tout le temps une fuite, soit je dois frapper les pointeurs directement dans le bloc où le travail principal est effectué.

Tout ce qui est disponible... mon message ci-dessus
 
equivalent23:

Je peux vous donner un exemple ?

C'est juste que l'exemple que j'ai donné est tiré de la documentation et qu'il n'est pas clair comment cela devrait fonctionner...

Voici comment cela fonctionne. Mais complètement hors de la documentation :/ (Mais une fois de plus, je me suis exercé sur les pointeurs)

#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:

Exécuter :

peut être fait beaucoup plus simplement... la virtualisation :


Ce n'est pas de ça que je parle. Il ne s'agit pas d'utiliser simplement des pointeurs, mais un tableau de ces pointeurs avec un type de classe de base.

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

Peu importe qu'il s'agisse d'un simple tableau ou d'un tableau de pointeurs, seul ce qui est écrit dans la classe de base fonctionne et est disponible.

Ou peut-être que je rate quelque chose.

Par exemple, une classe de base légèrement modifiée (conçue comme une 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); }// возвращает площадь фигуры

};

Si nous entassons tous ces éléments dans le tableau, nous aurons accès au moins aux fonctionnalités déclarées dans la classe de base.

La question est de savoir comment accéder à la fonctionnalité par descendant si le tableau est de type classe de base (c'est-à-dire que le tableau est de type CShape) ?

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

ce n'est pas ce dont je parle. Il ne s'agit pas d'utiliser simplement des pointeurs, mais un tableau de ces pointeurs avec un type de classe de base.

La question est de savoir comment accéder à la fonctionnalité par un descendant si le tableau est de type classe de base (c'est-à-dire que le tableau est de type CShape) ?

J'ai écrit sur la dernière page comment :

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

Même code, mais avec un tableau :

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:

C'est comme ça que ça marche. Mais complètement en dehors de la documentation :/

Eh bien, je veux dire la même chose, vous devriez au moins désigner toutes les fonctions dans une classe de base (sinon elles ne seront pas accessibles).
 
AlexSTAL:

Exécuter :

Pour quelque chose comme ça :

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

devrait être arraché avec la confiscation du clavier.

En C++, vous pouvez vous déplacer dans la hiérarchie des classes avec dynamic_cast, ce qui n'est pas apprécié là non plus. Dans MQL, cela peut provoquer des plantages implicites qui ne peuvent pas être facilement résolus, car le bogue se trouve à un endroit complètement différent.

Par conséquent, je déconseille fortement l'utilisation de ce type de conversion. C'est-à-dire, du tout. Aux ancêtres s'il vous plaît, aux enfants ni.

 
TheXpert:

Pour quelque chose comme ça :

vous devriez enlever vos mains et vous faire confisquer votre clavier.

En C++, vous pouvez vous déplacer dans la hiérarchie des classes en utilisant dynamic_cast, et ce n'est pas apprécié là non plus. Dans MQL, cela peut provoquer des plantages implicites qui ne peuvent pas être facilement résolus, car le bogue se trouve à un endroit complètement différent.

Par conséquent, je déconseille catégoriquement l'utilisation d'une telle conversion. C'est-à-dire, pas du tout. Aux ancêtres s'il vous plaît, pas aux enfants.

Quelle est la façon polie de répondre....

Si le programmeur est trop bête, alors une simple opération 1+1 peut provoquer des plantages implicites.....

Et je tiens à souligner que MQL5 n'est pas C++...

C'est juste une possibilité, pas une question d'application.....

 
AlexSTAL:

Même code, mais avec un tableau :


1. Supprimez m_radius() de l'ancêtre, il n'est pas dans l'exemple. :) Et vous n'obtiendrez aucun résultat avec elle dans OnStart() ;

2. la ligne "delete Base[0]" peut-elle être déplacée ailleurs ? Par exemple, si ce n'est pas un script mais un hibou et que j'ai toujours besoin des données dans le tableau.

J'ai eu des fuites de mémoire tout de suite. J'ai dû passer aux structures pour cette raison...

 
Interesting:

1. Supprimez m_radius(), il n'est pas présent dans l'exemple. Et on ne peut pas l'utiliser dans OnStart() ;

2. Puis-je déplacer la ligne de suppression Base[0] ailleurs ? Disons que ce n'est pas un script mais un hibou, et que j'ai toujours besoin des données dans le tableau.

J'ai eu une fuite de mémoire tout de suite. J'ai dû passer aux structures pour cette raison...

1) Enlevé, il fonctionne :

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) L'essentiel est de le supprimer avant la fin du programme... Mais si vous avez créé ce pointeur dans une fonction, vous devez prendre soin de le sauvegarder dans un endroit global...
Raison: