Biblioteca de clases genéricas - errores, descripción, preguntas, características de uso y sugerencias - página 21

 
fxsaber:

Sólo tenemos que sobrecargar GetHashCode para el tipo requerido en lugar de iniciar IEqualityComparable.

En este caso los extremos están muy lejos y el posible error aparecerá en algún lugar en las profundidades de la biblioteca. Y entonces adivinar por qué no se encuentra alguna función y de quién es la culpa. Y las interfaces garantizan de antemano que todas las funciones necesarias ya están definidas en el objeto.

 
Alexey Navoykov:

En este caso, los extremos van muy lejos, y el posible error se produce en algún lugar en las profundidades de la biblioteca. Y entonces adivinar por qué no se encuentra alguna función y de quién es la culpa. Y las interfaces garantizan de antemano que todas las funciones necesarias ya están definidas en el objeto.

¿Puede mostrar un ejemplo para MqlTick?

 
Alexey Navoykov:

Y las interfaces garantizan de antemano que todas las funciones necesarias ya están definidas en el objeto.

Sí, excepto que estas clases pretenden ser universales y deben funcionar para todos los tipos desde el principio.

 
fxsaber:

¿Puede mostrar un ejemplo para 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; }
};
Por supuesto, están los costes de tener que poner una clase, más el control del puntero.
 
Alexey Navoykov:
Aquí hay costos, por supuesto, que tendremos que poner en un cheque de clase más puntero.

Gracias, pero no veo cuál es la ventaja de este enfoque en la práctica.

En SB, el código es el siguiente

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

Resulta que los bailes propuestos sólo para evitar la sobrecarga de este GetHashCode. Pero, ¿merece la pena en este caso?

 
fxsaber:

Gracias, pero no veo cuál es la ventaja de este enfoque en la práctica.

En SB, el código es el siguiente

Resulta que los bailes propuestos sólo para evitar la sobrecarga de este GetHashCode. Pero, ¿merece la pena en este caso?

Si la velocidad es crucial, será mejor que la sobrecargue.

La cuestión es que en .NET, de donde se ha portado esta biblioteca, todos los tipos incorporados ya tienen interfaces desde el principio. Así es como se define int, también conocido como Int32:

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

Por eso no hay sobrecarga allí.

Y la propia clase CKeyValuePair se declararía de forma un poco diferente.

Aunque sería mejor dedicar ese tiempo a mejorar la funcionalidad del lenguaje. Entonces se podría haber copiado toda la librería de .Net y todo habría funcionado.

 
Alexey Navoykov:
Aquí hay costos, por supuesto, que usted tendrá que poner en una clase, además de cheque puntero.
¿Cuál es el problema de poner este código en la sobrecarga GetHashCode? Entonces no es necesario heredar de la interfaz
 
Combinador:
¿Cuál es el problema de meter este código en la sobrecarga GetHashCode? entonces no hay necesidad de heredar de la interfaz

Es posible, por supuesto. Pero hace más difícil controlar el proceso. Supongamos que tienes un montón de diferentes GetHashCodes, dispersos por todo el código, y cuáles de ellos son llamados aquí (y dónde se encuentran), puede ser difícil de entender. Por ejemplo, cuando se llama a una función, el argumento hace un casting a algún otro tipo. En C# esto puede ser la razón por la que las posibilidades de plantillas son muy limitadas en comparación con C++

 
Alexey Navoykov:

Es posible, por supuesto. Pero complica el control del proceso.

En C++ esta interfaz es innecesaria, la interacción normal se logra mediante la simple sobrecarga del operador <, y este operador puede ser definido fuera de la CLASE.

Creo que es mucho más fácil y lacónico que convertir tales construcciones. Pero se necesita soporte nativo para la sobrecarga del operador < fuera de una clase.

Pero para las estructuras incrustadas no hay nada más que sobrecargar GetHashCode, porque el stub es horrible y la herencia es imposible. La herencia desde la estructura es una solución de muleta, porque obliga a usar funciones estándar para fundir manualmente la estructura a la herencia del usuario, para que todo funcione como se pretende.
 
Combinador:

La herencia de una estructura es una solución de muleta, porque te obliga a lanzar manualmente la estructura a un heredero personalizado cuando se utilizan funciones estándar para que todo funcione como se pretende.

Aparentemente no te refieres a la herencia, sino a la envoltura de una clase sobre una estructura.

En realidad, este "forzamiento" es también un inconveniente de la funcionalidad de MQL, ya que no hay manera de sobrecargar el operador de fundición, de lo contrario la clase podría ser fácilmente fundida a la estructura implícitamente.

Pero nadie se molestó... El desarrollo está estancado desde hace 2 años, sin mejoras ni innovaciones.

Mientras que los propios desarrolladores se quejan aquí de la falta de múltiples interfaces y otras características, pero siguen comiéndose un cactus).