Generische Klassenbibliothek - Bugs, Beschreibung, Fragen, Nutzungsmöglichkeiten und Vorschläge - Seite 21

 
fxsaber:

Wir müssen nur GetHashCode für den erforderlichen Typ überladen, anstatt IEqualityComparable zu starten.

In diesem Fall ist das Ende sehr weit weg und ein möglicher Fehler wird irgendwo in den Tiefen der Bibliothek auftauchen. Dann muss man raten, warum eine Funktion nicht gefunden wird und wessen Schuld es ist. Und Schnittstellen garantieren im Voraus, dass alle benötigten Funktionen bereits im Objekt definiert sind.

 
Alexey Navoykov:

In diesem Fall gehen die Enden sehr weit, und der mögliche Fehler tritt irgendwo in den Tiefen der Bibliothek auf. Und dann raten, warum irgendeine Funktion nicht gefunden wird und wessen Schuld das ist. Und Schnittstellen garantieren im Voraus, dass alle notwendigen Funktionen bereits im Objekt definiert sind.

Können Sie ein Beispiel für MqlTick zeigen?

 
Alexey Navoykov:

Und Schnittstellen stellen im Vorfeld sicher, dass alle notwendigen Funktionen bereits im Objekt definiert sind.

Ja, außer, dass diese Klassen den Anspruch erheben, universell zu sein und für alle Typen sofort funktionieren müssen.

 
fxsaber:

Können Sie ein Beispiel für MqlTick zeigen?

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; }
};
Dazu kommen natürlich noch die Kosten für den Unterricht und die Zeigerprüfung.
 
Alexey Navoykov:
Natürlich gibt es hier Kosten, die wir in eine Klasse plus Zeigerprüfung stecken müssen.

Danke, aber ich kann nicht erkennen, wo der Vorteil dieses Ansatzes in der Praxis liegt?

In SB sieht der Code folgendermaßen aus

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

Es stellt sich heraus, dass die vorgeschlagenen Tänze nur dazu dienen, eine Überlastung dieses GetHashCode zu vermeiden. Aber ist es in diesem Fall die Mühe wert?

 
fxsaber:

Danke, aber ich kann nicht erkennen, wo der Vorteil dieses Ansatzes in der Praxis liegt?

In SB sieht der Code folgendermaßen aus

Es stellt sich heraus, dass die vorgeschlagenen Tänze nur dazu dienen, eine Überlastung dieses GetHashCode zu vermeiden. Aber ist es in diesem Fall die Mühe wert?

Wenn Geschwindigkeit entscheidend ist, sollte man sie besser überlasten.

Der Punkt ist, dass in .NET, von wo diese Bibliothek portiert wurde, alle eingebauten Typen bereits von Anfang an Schnittstellen haben. So ist int, auch bekannt als Int32, definiert:

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

Aus diesem Grund gibt es dort keine Überlastung.

Und die Klasse CKeyValuePair selbst würde ein wenig anders deklariert werden.

Obwohl es besser wäre, diese Zeit in die Verbesserung der Funktionalität der Sprache zu investieren. Dann hätte man die gesamte .Net-Bibliothek kopieren können und alles hätte funktioniert.

 
Alexey Navoykov:
Hier fallen natürlich Kosten an, die Sie in eine Klasse stecken müssen, plus Zeigerprüfung.
Was ist das Problem, wenn Sie diesen Code in die GetHashCode-Überladung einfügen? Dann brauchen Sie nicht von der Schnittstelle zu erben
 
Kombinator:
Wo liegt das Problem, wenn man diesen Code in die GetHashCode-Überladung schiebt? Dann ist es nicht nötig, von der Schnittstelle zu erben

Das ist natürlich möglich. Aber es macht es schwieriger, den Prozess zu kontrollieren. Angenommen, Sie haben einen Haufen verschiedener GetHashCodes, die über den gesamten Code verstreut sind, und welche davon hier aufgerufen werden (und wo sie sich befinden), kann schwer zu verstehen sein. Wenn Sie beispielsweise eine Funktion aufrufen, wird das Argument auf einen anderen Typ gecastet. In C# sind die Möglichkeiten der Vorlagen im Vergleich zu C++ deshalb sehr begrenzt

 
Alexey Navoykov:

Das ist natürlich möglich. Aber es erschwert die Prozesskontrolle.

In C++ ist diese Schnittstelle unnötig, die normale Interaktion wird durch einfaches Überladen des <-Operators erreicht, und dieser Operator kann außerhalb der CLASS definiert werden.

Ich denke, es ist viel einfacher und lakonischer, als solche Konstruktionen zu drehen. Aber Sie brauchen native Unterstützung für das Überladen des Operators < außerhalb einer Klasse.

Aber für eingebettete Strukturen gibt es nichts außer dem Überladen von GetHashCode, weil der Stub schrecklich ist und Vererbung unmöglich ist. Vererbung von Struktur ist eine Krückenlösung, weil es zwingt, mit Standardfunktionen manuell Struktur zu Benutzer Vererbung, so dass alles wie beabsichtigt funktionieren wird.
 
Kombinator:

Die Vererbung von einer Struktur ist eine Krückenlösung, denn sie zwingt Sie dazu, die Struktur manuell in einen benutzerdefinierten Erben zu übertragen, wenn Sie Standardfunktionen verwenden, damit alles wie vorgesehen funktioniert.

Offenbar meinen Sie nicht die Vererbung, sondern das Wrapping von einer Klasse über eine Struktur?

Eigentlich ist dieses "Erzwingen" auch ein Nachteil der MQL-Funktionalität, da der Cast-Operator nicht überladen werden kann, sonst würde die Klasse einfach implizit in die Struktur gecastet werden.

Aber niemand hat sich darum gekümmert... Die Entwicklung stagniert nun schon seit 2 Jahren, keine Verbesserungen und Innovationen.

Die Entwickler selbst beklagen sich hier über das Fehlen mehrerer Schnittstellen und anderer Funktionen, essen aber weiterhin einen Kaktus).

Grund der Beschwerde: