Biblioteca de classes genéricas - bugs, descrição, perguntas, recursos de uso e sugestões - página 21

 
fxsaber:

Só precisamos de sobrecarregar o GetHashCode para o tipo necessário, em vez de iniciar o IEqualityComparable.

Neste caso os fins estão muito longe e um possível erro aparecerá em algum lugar nas profundezas da biblioteca. E então adivinhe por que alguma função não é encontrada e de quem é a falha. E as interfaces garantem antecipadamente que todas as funções necessárias já estão definidas no objeto.

 
Alexey Navoykov:

Neste caso, os fins vão muito longe, e o possível erro ocorre em algum lugar nas profundezas da biblioteca. E então adivinhe por que alguma função não é encontrada e de quem é a falha. E as interfaces garantem antecipadamente que todas as funções necessárias já estão definidas no objeto.

Você pode mostrar um exemplo para o MqlTick?

 
Alexey Navoykov:

E as interfaces garantem antecipadamente que todas as funções necessárias já estão definidas no objeto.

Sim, exceto que essas aulas afirmam ser universais e devem funcionar para todos os tipos fora da caixa.

 
fxsaber:

Você pode mostrar um exemplo para o 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; }
};
Há, é claro, os custos de ter que colocar em uma aula, mais a verificação do ponteiro.
 
Alexey Navoykov:
Há custos aqui, é claro, que teremos que colocar em uma aula mais verificação de ponteiro.

Obrigado, mas não consigo ver qual é a vantagem desta abordagem na prática?

Em SB, o código é assim

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

Acontece que as danças propostas apenas para evitar a sobrecarga deste GetHashCode. Mas será que vale a pena o trabalho neste caso?

 
fxsaber:

Obrigado, mas não consigo ver qual é a vantagem desta abordagem na prática?

Em SB, o código é assim

Acontece que as danças propostas apenas para evitar a sobrecarga deste GetHashCode. Mas será que vale a pena o trabalho neste caso?

Se a velocidade é crucial, é melhor sobrecarregá-la.

A questão é que em .NET, de onde esta biblioteca foi portada, todos os tipos incorporados já possuem interfaces desde o início. É assim que se define int, aka Int32:

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

É por isso que não há sobrecarga lá.

E a própria classe CKeyValuePair seria declarada um pouco diferente.

Embora fosse melhor passar este tempo a melhorar a funcionalidade do idioma, então toda a biblioteca .Net poderia ter sido copiada e tudo teria funcionado.

 
Alexey Navoykov:
Há custos aqui, claro, que você terá que colocar em uma aula, mais verificação de ponteiro.
Qual é o problema em colocar este código na sobrecarga do GetHashCode? Então você não precisa herdar da interface
 
Combinador:
Qual é o problema de enfiar este código na sobrecarga do GetHashCode? então não há necessidade de herdar da interface

É possível, é claro. Mas isso torna mais difícil controlar o processo. Suponha que você tenha um monte de diferentes GetHashCodes, espalhados pelo código, e quais deles são chamados aqui (e onde eles estão localizados), pode ser difícil de entender. Por exemplo, ao chamar uma função, o argumento é lançado para algum outro tipo. Em C# isto pode ser a razão pela qual as possibilidades de modelos são muito limitadas em comparação com C++

 
Alexey Navoykov:

É possível, é claro. Mas isso complica o controlo do processo.

Em C++ esta interface é desnecessária, a interação normal é obtida pela simples sobrecarga de < operador, e este operador pode ser definido fora da CLASSE.

Acho que é muito mais fácil e lacónico do que transformar tais construções. Mas é preciso apoio nativo para o operador de sobrecarga < fora de uma classe.

Mas para estruturas embutidas não há nada além de sobrecarregar o GetHashCode, porque o stub é horrível e a herança é impossível. A herança da estrutura é uma solução de muleta, porque obriga o uso de funções padrão a lançar manualmente a estrutura para a herança do usuário, assim tudo funcionará como pretendido.
 
Combinador:

A herança de uma estrutura é uma solução de muleta, pois obriga-o a lançar manualmente a estrutura a um herdeiro personalizado quando utiliza funções padrão para que tudo funcione como pretendido.

Aparentemente não se refere à herança, mas ao embrulho de uma classe sobre uma estrutura?

Na verdade, tal "forçamento" também é uma desvantagem da funcionalidade MQL, pois não há como sobrecarregar o operador fundido, caso contrário a classe seria facilmente fundida na estrutura implicitamente.

Mas ninguém se preocupou... O desenvolvimento está estagnado há 2 anos, sem melhorias e inovações.

Enquanto os próprios desenvolvedores aqui reclamam da falta de múltiplas interfaces e outras características, mas continuam a comer um cacto).

Razão: