Bibliothèque de classes génériques - bogues, description, questions, caractéristiques d'utilisation et suggestions - page 21

 
fxsaber:

Il suffit de surcharger GetHashCode pour le type requis au lieu de lancer IEqualityComparable.

Dans ce cas, les fins sont très éloignées et une erreur éventuelle apparaîtra quelque part dans les profondeurs de la bibliothèque. Il faut ensuite deviner pourquoi une fonction n'est pas trouvée et à qui la faute. Et les interfaces garantissent à l'avance que toutes les fonctions nécessaires sont déjà définies dans l'objet.

 
Alexey Navoykov:

Dans ce cas, les extrémités vont très loin, et l'erreur éventuelle se produit quelque part dans les profondeurs de la bibliothèque. Il faut alors deviner pourquoi telle ou telle fonction est introuvable et à qui la faute. Et les interfaces garantissent à l'avance que toutes les fonctions nécessaires sont déjà définies dans l'objet.

Pouvez-vous montrer un exemple pour MqlTick?

 
Alexey Navoykov:

Et les interfaces garantissent à l'avance que toutes les fonctions nécessaires sont déjà définies dans l'objet.

Oui, sauf que ces classes prétendent être universelles et doivent fonctionner pour tous les types dès le départ.

 
fxsaber:

Pouvez-vous montrer un exemple pour MqlTick?

class CMqlTick : public IEqualityComparable<CMqlTick*>
{
 public: 
   MqlTick _tick;
   bool    Equals(CMqlTick* obj) { return obj!=NULL && obj._tick.time==_tick.time; }
   int     HashCode(void)        { return _tick.time; }
};
Il y a bien sûr les frais d'inscription à un cours, plus le contrôle du pointeur.
 
Alexey Navoykov:
Il y a bien sûr des coûts ici, que nous devrons mettre dans un contrôle de classe plus pointeur.

Merci, mais je ne vois pas quel est l'avantage de cette approche en pratique ?

Dans SB, le code est le suivant

//+------------------------------------------------------------------+
//| Class CKeyValuePair<TKey, TValue>.                               |
//| Usage: Defines a key/value pair that can be set or retrieved.    |
//+------------------------------------------------------------------+
template<typename TKey,typename TValue>
class CKeyValuePair: public IComparable<CKeyValuePair<TKey,TValue>*>
  {
protected:
   TKey              m_key;
   TValue            m_value;

public:
                     CKeyValuePair(void)                                              {   }
                     CKeyValuePair(TKey key,TValue value): m_key(key), m_value(value) {   }
                    ~CKeyValuePair(void)                                              {   }
   //--- methods to access protected data
   TKey              Key(void)           { return(m_key);   }
   void              Key(TKey key)       { m_key=key;       }
   TValue            Value(void)         { return(m_value); }
   void              Value(TValue value) { m_value=value;   }
   //--- method to create clone of current instance
   CKeyValuePair<TKey,TValue>*Clone(void) { return new CKeyValuePair<TKey,TValue>(m_key,m_value); }
   //--- method to compare keys
   int               Compare(CKeyValuePair<TKey,TValue>*pair) { return ::Compare(m_key,pair.m_key); }
   //--- method for determining equality
   bool              Equals(CKeyValuePair<TKey,TValue>*pair) { return ::Equals(m_key,pair.m_key); }
   //--- method to calculate hash code   
   int               HashCode(void) { return ::GetHashCode(m_key); }

Il s'avère que les danses proposées ne servent qu'à éviter la surcharge de ce GetHashCode. Mais cela en vaut-il la peine dans ce cas ?

 
fxsaber:

Merci, mais je ne vois pas quel est l'avantage de cette approche en pratique ?

Dans SB, le code est le suivant

Il s'avère que les danses proposées ne servent qu'à éviter de surcharger ce GetHashCode. Mais cela en vaut-il la peine dans ce cas ?

Si la vitesse est cruciale, il vaut mieux la surcharger.

Le fait est que dans .NET, d'où cette bibliothèque a été portée, tous les types intégrés ont déjà des interfaces dès le début. C'est ainsi que int, alias Int32, est défini :

public struct Int32 : IComparable, IFormattable, IConvertible, 
        IComparable<int>, IEquatable<int>

C'est pourquoi il n'y a pas de surcharge à cet endroit.

Et la classe CKeyValuePair elle-même serait déclarée un peu différemment.

Il serait préférable de consacrer ce temps à l'amélioration de la fonctionnalité du langage, car toute la bibliothèque .Net aurait pu être copiée et tout aurait fonctionné.

 
Alexey Navoykov:
Il y a bien sûr des coûts, qu'il faudra mettre dans une classe, plus le contrôle des pointeurs.
Quel est le problème de mettre ce code dans la surcharge GetHashCode ? Ainsi, vous n'avez pas besoin d'hériter de l'interface
 
Combinateur:
Quel est le problème si l'on insère ce code dans la surcharge GetHashCode ? Il n'est pas nécessaire d'hériter de l'interface.

C'est possible, bien sûr. Mais cela rend plus difficile le contrôle du processus. Supposons que vous ayez un tas de GetHashCodes différents, disséminés dans le code, et qu'il soit difficile de comprendre lesquels sont appelés ici (et où ils se trouvent). Par exemple, lors de l'appel d'une fonction, l'argument est converti en un autre type. En C#, c'est peut-être la raison pour laquelle les possibilités de modèles sont très limitées par rapport au C++.

 
Alexey Navoykov:

C'est possible, bien sûr. Mais cela complique le contrôle du processus.

En C++, cette interface est inutile, l'interaction normale est réalisée par une simple surcharge de l'opérateur <, et cet opérateur peut être défini en dehors de la CLASSE.

Je pense que c'est beaucoup plus facile et laconique que de tourner de telles constructions. Mais vous avez besoin d'un support natif pour surcharger l'opérateur < en dehors d'une classe.

Mais pour les structures intégrées, il n'y a rien d'autre que de surcharger GetHashCode, parce que le stub est horrible et que l'héritage est impossible. L'héritage à partir de la structure est une solution de béquille, parce qu'elle oblige à utiliser les fonctions standard pour couler manuellement la structure vers l'héritage utilisateur, afin que tout fonctionne comme prévu.
 
Combinateur:

L'héritage d'une structure est une solution de secours, car elle vous oblige à convertir manuellement la structure en un héritier personnalisé lorsque vous utilisez des fonctions standard pour que tout fonctionne comme prévu.

Apparemment, vous ne parlez pas d'héritage, mais d'enveloppement d'une classe sur une structure ?

En fait, un tel "forçage" est également un inconvénient de la fonctionnalité MQL puisqu'il n'y a aucun moyen de surcharger l'opérateur cast, sinon la classe pourrait facilement être castée vers la structure implicitement.

Mais personne ne s'en est soucié... Le développement stagne depuis 2 ans maintenant, aucune amélioration ni innovation.

Alors que les développeurs eux-mêmes se plaignent ici de l'absence d'interfaces multiples et d'autres fonctionnalités, mais continuent à manger un cactus).