Questions sur la POO dans MQL5 - page 83

 

Yaah... A quel point les gens sont dérangés par les const(((.

Pour comprendre les méthodes avec le spécificateur const

class CTest{
   int i;
public:
   CTest(int _i):i(_i){}
   int Get() const {return i;}
   int Get()   {return 2*i;}
};

void OnStart()
  {
   const CTest a(5);
   CTest b(8);
   Print(a.Get()); //5
   Print(b.Get()); //16
  }

Maintenant, faites

   //int Get() const {return i;}

et ensuite faire l'inverse :

//   int Get()   {return 2*i;}

)))

 
Alexandr Andreev:

Egalement une variante du même code.


C'est avec les constantes.

Et vous êtes sûr que l'entrée

Compare(CObject const *node,int const mode=0)

♪ you'll always feed ♪

CChartObjectRectangleX*

pour écrire sans vérifier ?

return (  Time(1)-dynamic_cast<const ME*>(node).Time(1));

?

 
Alexandr Andreev:

la variante sans la constitution puisque la classe de base n'a pas de référence aux paramètres d'entrée fonctionnera également correctement, bien que ce style ne soit pas très astucieux

Cela ne fonctionnera pas de cette façon. Vous ne pouvez pas modifier la signature dans Compare. Il est principalement nécessaire pour la méthode QuickSort, qui est incluse dans SB, pour que le tri régulier fonctionne.

Si vous changez la signature, ce n'est pas une surcharge de la fonction virtuelle mais une surcharge et c'est l'appel d'une méthode de la classe de base CObject qui retourne 0 ;

Bien sûr, cela peut être résolu par des wrappers (décoration) vers les conteneurs, mais pourquoi ces mouvements inutiles, ou alors ne pas utiliser SB et tout écrire à partir de zéro.

 
Vladimir Simakov:

Il semble que ce soit le même que le vôtre, mais avec moins de lettres. C'est donc une question de goût, mais j'ai supprimé la variable supplémentaire (le compilateur l'aurait très probablement supprimée dans le cadre de l'optimisation).

En ce qui concerne ma vérification du nœud. Il doit être remplacé par CheckPointer(node)==POINTER_INVALID, mais c'est une surcharge - un appel de fonction. Même si c'est inlined, il y a au moins déréférencement et vérification du drapeau d'état. Si vous n'avez écrit qu'une bibliothèque ou un programme concret qui utilisera les méthodes de comparaison, il est préférable d'utiliser !node et on code pour surveiller les pointeurs invalides. Si vous êtes trop paresseux pour faire attention aux pointeurs ou si c'est une bibliothèque pour les outsiders, seulement CheckPointer(node)==POINTER_INVALID.

Si vous retirez le spécificateur const que vous avez mis en évidence, vous ne pouvez pas appeler ces méthodes à partir d'un objet constant.

UPD : le contrôle en surbrillance peut être supprimé, comme il l'est dans les méthodes appelées.

Vladimir, dans ce cas précis, CheckPointer est redondant. dynamic_cast renverra NULL en cas d'échec du cast, y compris si le pointeur est cassé. Veuillez me corriger si je me trompe. Testé il y a longtemps, le test a pris 5 secondes).

Mécanisme de fonctionnement de CheckPointer (en termes simples, je ne maîtrise pas les termes de bas niveau) - il cherche par le pointeur quel type d'objet, dynamique ou statique, si nous ne pouvons pas obtenir l'information, cela signifie POINTER_INVALID. Cela peut être le cas lorsque l'objet dynamique a été supprimé, je ne sais pas d'autres situations, ou téléchargé des déchets à l'indicateur, mais il doit vérifier le compilateur, si vous ne pouvez pas trouver des failles.

et dynamic_cast fait de même, en vérifiant également si le pointeur peut être converti dans le type requis, c'est-à-dire s'il s'agit d'un pointeur de ce type ou d'une classe enfant.

Si le pointeur est cassé, dynamic_cast ne détecte rien et renvoie NULL.

C'est pourquoi je n'ai pas utilisé CheckPointer. Mais j'utilise généralement ce chèque partout où il n'y a pas de danger. Après tout, pour trouver une erreur dans un logiciel, qui n'est pas tombé, un peu plus facile il semble).

Et qu'en est-il des méthodes non-const - en théorie, nous pouvons avoir une méthode comme GetRatingByAnyFormula() { m_rating01=Formula01() ; return m_rating01;}

serait assez gênant s'il n'était pas utilisé tout de suite dans le tri, c'est-à-dire qu'il faudrait d'abord compter la note et ensuite appeler le tri par celle-ci. Ou, comme déjà dit, écrivez votre propre SB à partir de zéro).

 
Aleksey Mavrin:

Ce n'est pas bon. La signature ne peut pas être modifiée dans Compare. C'est principalement dans le but de faire fonctionner QuickSort, la méthode de tri régulière incluse dans SB.

Si vous modifiez la signature, il ne s'agit pas d'une surcharge de la fonction virtuelle, mais d'une surcharge et la méthode de la classe de base CObject sera appelée, avec un retour de 0 ;

Bien sûr, cela peut être résolu par des wrappers (décoration) vers les conteneurs, mais pourquoi ces mouvements inutiles, ou ne pas utiliser SB et tout écrire à partir de zéro ?

La manière la plus correcte est de ne pas écrire sur le µl.

 
Aleksey Mavrin:

Vladimir, dans ce cas, CheckPointer est redondant. dynamic_cast renverra NULL en cas d'échec du cast, y compris si le pointeur est cassé. Veuillez me corriger si je me trompe. Testé il y a longtemps, le test a pris 5 secondes).

Mécanisme de fonctionnement de CheckPointer (en termes simples, je ne maîtrise pas les termes de bas niveau) - il cherche par le pointeur quel type d'objet, dynamique ou statique, si nous ne pouvons pas obtenir l'information, cela signifie POINTER_INVALID. Cela peut être le cas si l'objet dynamique a été supprimé, d'autres situations que je ne sais pas, ou téléchargé des déchets à l'indicateur, mais il doit vérifier le compilateur, si vous ne pouvez pas trouver des failles.

et dynamic_cast fait la même chose, en vérifiant également si le pointeur peut être converti dans le type requis, c'est-à-dire s'il s'agit d'un pointeur de ce type ou d'une classe enfant.

Si le pointeur est cassé, dynamic_cast ne détecte rien et renvoie NULL.

C'est pourquoi je n'ai pas utilisé CheckPointer. Mais j'utilise généralement ce chèque partout où il n'y a pas de danger. Après tout, pour trouver une erreur dans un logiciel, qui n'est pas tombé, un peu plus facile il semble).

Et qu'en est-il des méthodes non-const - en théorie, nous pouvons avoir une méthode comme GetRatingByAnyFormula() { m_rating01=Formula01() ; return m_rating01;}

serait assez gênant s'il n'était pas utilisé tout de suite dans le tri, c'est-à-dire qu'il faudrait d'abord compter la note et ensuite appeler le tri par celle-ci. Ou vous pouvez écrire votre propre SB à partir de zéro comme déjà mentionné).

  1. Les méthodes de comparaison sont définies comme publiques, ce qui signifie que n'importe qui, peu importe les efforts que vous faites pour l'expliquer dans les spécifications, y poussera un descripteur non valide. Bien sûr, si ce n'est pas une bibliothèque, mais juste pour vous-même, vous n'êtes pas obligé de le faire.
  2. Je ne sais pas comment fonctionne CheckPointer, il y a jusqu'à . Mais dans tous les cas, il s'agit de l'horloge du processeur et de l'accès à la mémoire (il pourrait facilement s'agir de mémoire virtuelle également).
  3. À propos des méthodes avec le spécificateur const. Si vous écrivez une bibliothèque, vous devez toujours garder à l'esprit que l'objet peut avoir besoin d'une constante, donc dans ces méthodes, qui ne changent pas l'état de l'objet, comme il est souhaitable. Bien que, jusqu'à présent, pour ma part, je ne m'en préoccupe pas vraiment.
  4. En écrivant votre propre système, c'est probablement la bonne décision. C'est juste des perspectives intéressantes dans le rapport salaire / travail n'est pas encore visible, et donc ne sera pas terminé, donc pour leurs propres besoins seulement).
 
Vladimir Simakov:

A propos de ma vérification du nœud. Il devrait être remplacé par CheckPointer(node)==POINTER_INVALID, mais il s'agit d'une surcharge, d'un appel de fonction.

Le problème ne se situe pas au niveau de l'overhead mais dans le fait qu'un pointeur cassé va changer la logique du programme, c'est-à-dire qu'au lieu de détecter le problème, vous allez l'enterrer encore plus profondément.

CheckPointer ne doit être utilisé qu'à des fins de débogage, ou comme implémentation d'un pointeur faible.

 
Vladimir Simakov:
  1. Les méthodes de comparaison sont définies comme publiques, donc n'importe quel outsider, même si vous le lui dites avec force dans les spécifications, y placera un descripteur invalide (appelons les choses par leur nom). Bien sûr, si ce n'est pas une bibliothèque, mais juste pour vous-même, vous n'êtes pas obligé de le faire.
  2. Je ne sais pas comment fonctionne CheckPointer, il y a jusqu'à . Mais dans tous les cas, il s'agit de l'horloge du processeur et de l'accès à la mémoire (il pourrait facilement s'agir de mémoire virtuelle également).
  3. À propos des méthodes avec le spécificateur const. Si vous écrivez une bibliothèque, vous devez toujours garder à l'esprit que l'objet peut avoir besoin d'une constante, donc dans ces méthodes, qui ne changent pas l'état de l'objet, comme il est souhaitable. Mais jusqu'à présent, pour ma part, je ne m'en préoccupe pas vraiment.
  4. En écrivant votre propre système, c'est probablement la bonne décision. C'est juste des perspectives intéressantes dans le rapport salaire / travail n'est pas encore visible, et donc il n'y aura rien de finalisé, donc seulement pour leurs propres besoins).

1. Je ne discute pas, mais ce que je disais c'est que vous n'avez PAS besoin d'un CheckPointer (même pour les outsiders), parce que dynamic_cast ne peut PAS retourner un pointeur non-invalide, seulement NULL.

2. C'est même intéressant, mais je n'arrive pas à penser immédiatement à un exemple qui permettrait d'obtenir un pointeur non invalide autrement qu'en tuant l'objet dynamique ou en "salissant" la mémoire directement en travaillant dessus.

Je suppose qu'il existe encore de tels moyens, mais ils se situent tous sur le plan du contournement des contrôles du compilateur.

3,4 D'accord.

P.S.

J'ai dû me tromper pour la première. Le test dit le contraire. Ce doit être juste une impression).

void OnStart()
  {
      CChartObjectRectangle *base = new CChartObjectRectangle();
      CChartObjectRectangleX *rect = new CChartObjectRectangleX();
       CChartObjectRectangle * dbase  ;
      const CChartObjectRectangleX *drect  ;
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL," check? ",!dbase, " broken? ", EnumToString( CheckPointer(dbase) ));
      dbase=dynamic_cast< CChartObjectRectangle *>  (base);
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL, " check? ",!dbase," broken? ", EnumToString( CheckPointer(dbase) ));
      delete base;
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL," check? ",!dbase, " broken? ", EnumToString( CheckPointer(dbase) ));
      dbase=dynamic_cast< CChartObjectRectangle *>  (base);   
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL," check? ",!dbase, " broken? ", EnumToString( CheckPointer(dbase) ));   
  }
 
Est-il possible de déclarer un tableau statique dans la section publique de la classe et de l'initialiser dans le constructeur ? (comme ci-dessous) (ou seulement élément par élément ?)
 bool Mass[5] = { false, true, false, true, true };
 
Pavel Verveyko:
Un tableau statique peut-il être déclaré dans la section publique de la classe et initialisé dans le constructeur ? (comme ci-dessous) (ou seulement élément par élément ?)

Vous pouvez initialiser un tableau local et effectuer un ArrayCopy vers le champ de tableau approprié :

class A{
public:
   bool Mass[5];
   A(){
       bool mass_init[5] = { false, true, false, true, true };
       ArrayCopy(Mass, mass_init);
   }
};
Raison: