Wie kann man Objekte dynamisch erstellen? (Einige OOP-Sachen) - Seite 2

 
Doerk Hilger:

Ich möchte nicht sagen, dass Sie es völlig falsch machen, aber Sie tun es, denn dies ist Strukturprogrammierung und nicht OOP. Der große Unterschied ist die Macht der Vererbung und Überladung. Übrigens kann man nicht wirklich von echten grafischen Objekten erben, aber man kann alles als Codeobjekt darstellen und von diesem Objekt aus auf eine Linie oder was auch immer verweisen. Das ist die Art und Weise, wie es normalerweise in jeder Klasse gemacht wird, egal ob es eine MFC- oder eine MQL-Klasse ist, es ist alles das Gleiche.

Wenn Ihre Zeilen Objekte sind, dann behandeln Sie sie als solche. Handeln Sie nicht mit Arrays außerhalb, tun Sie es innerhalb einer Klasse Sammlung und arbeiten Sie mit Zeigern. Werfen Sie einen Blick auf CWndContainer und machen Sie sich ein Bild davon. Diese Klasse ist ein Container, der hauptsächlich Zeiger-Arrays für CWnd-Objekte verwaltet. Gehen Sie einen Schritt weiter, Ihre Struktur sollte sein:

CObject als Basis für jedes Objekt

CPriceTimeObjects als Basis für jedes preis-/zeitbasierte Objekt, wie z.B. Linien, leitet sich von CObject ab. Es steuert die Erstellung, hält Zeit und Preis und ruft eine OnCreate() auf, die vom nächsten Erben verwendet werden kann. Es verfügt auch über eine Tick-Funktion, die ein virtuelles OnTick() aufruft, das dann von den Nachfolgern überladen wird.

CTrendLine als Basis für Trendlinien erbt von CPriceTimeObjects und behandelt OnCreate, wobei es die endgültige Linie mit der Funktion ObjectCreate erstellt. Sie sollte auch einen OnTick()-Handler haben, um auf Tick-Ereignisse zu reagieren, da sie preisabhängig sein soll, soweit ich das verstanden habe.

Daneben gibt es eine Containerklasse, die ein Zeigerarray verwaltet, das alle gewünschten CTimePriceObject-Objekte enthält. Sie erbt ebenfalls von CTimePriceObject und übergibt OnTick() an ihre "Kinder". Der Container hat auch eine Funktion, die das OnChartEvent() verarbeitet, um Linien hinzuzufügen oder zu entfernen. Er sollte auch eine Scan-Funktion haben, um alle existierenden Objekte für den Fall zu scannen, dass der Experte hinzugefügt wurde, nachdem Linien erstellt wurden. Darüber hinaus behandelt es das überladene OnTick() von CTimePrice, durchläuft das dortige Array und fragt jedes CTrendLine-Objekt, ob es sich irgendwie verantwortlich fühlt, zu reagieren, indem es die Tick-Funktion jedes Kindobjekts aufruft, das von einem virtuellen OnTick behandelt wird. Warum das Ganze noch einmal? Weil die CTrendLine diese Funktion auch von CTimePrice überlädt und somit diese Klasse auch von weiteren Erben mit weiteren Funktionen geerbt werden kann.

Sehr schön, Dorek.

Ich habe allerdings einige Fragen:

Warum muss der Container, der CTimePriceObject enthält, selbst von CTimePriceObject erben? Zum Beispiel erbt CIndicators in der Standardlib von CArrayObj und verweist höchstwahrscheinlich auf CIndicator, ohne es zu erben.
Ich weiß, dass es die Standard-Lib und nicht die regulären Arrays verwenden will, aber etwas an dem Konzept, dass ein Container eines Objekts einer bestimmten Art das Objekt selbst erben sollte, ist mir unklar (weil der Container selbst kein Objekt ist, das er enthält, d.h. es gibt keine "ist ein"-Beziehung), obwohl ich es für richtig halte.
Können Sie bitte Ihre Ansicht dazu erläutern?

Zweitens scheinen Sie das Framework von Grund auf neu zu entwickeln, ohne sich auf die Standardbibliothek zu stützen, wenn Sie sagen, dass CTrendLine die letzte Zeile mit der spracheigenen Funktion ObjectCreate erstellt.
Wann würden Sie empfehlen, die Standardbibliotheken selbst zu erweitern? Nehmen wir zum Beispiel an, ich möchte, dass alle CIndicator-Objekte der Standardbibliothek in der Lage sind zu sagen, wie oft der Preis einen Puffer in ihnen berührt hat
in den letzten X Bars. Wie würden Sie vorgehen, denn wenn Sie eine Basisklasse wie CIndicator oder CIndicatorBuffer erweitern, dann haben Sie alle abhängigen Objekte der Standardbibliothek, die von Ihrem
neuen CIndicator oder neuen CBuffer erben müssen, wie zum Beispiel CiMA. Würdest du all diese benutzerdefinierten Indikator-Klassen in deinen Ordner kopieren und ihre Vererbung auf deinen neuen CIndicatorBuffer ändern? Was passiert dann, wenn metaquotes etwas zu seinen Standard-CIndicatorBuffer- oder höheren Klassen hinzufügt?

Vielen Dank für die Einblicke.

BR

 

Willbur:

...

Wenn Sie diesen Weg gehen, sollte mein SmartLine-Objekt im MT5-Menü neben der Trendlinie, den Pfeilen, dem Textobjekt und all diesen Dingen erscheinen.

...

Wenn MT5 das zulässt, dann bleibt nur noch die Frage zu klären, wie das Objekt vom Terminalprogramm bei einer Kursänderung ausgelöst werden kann.

...
Das kann man mit mql5 nicht machen.
 
Amir Yacoby:

Sehr schön, Dorek.

Ich habe allerdings einige Fragen:

Warum muss der Container, der CTimePriceObject enthält, selbst von CTimePriceObject erben? Zum Beispiel erbt CIndicators in der Standardlib von CArrayObj und verweist höchstwahrscheinlich auf CIndicator, ohne es zu erben.
Ich weiß, dass es die Standard-Lib und nicht die regulären Arrays verwenden will, aber etwas an dem Konzept, dass ein Container eines Objekts einer bestimmten Art das Objekt selbst erben sollte, ist mir unklar (weil der Container selbst kein Objekt ist, das er enthält, d.h. es gibt keine "ist ein"-Beziehung), obwohl ich es für richtig halte.
Können Sie bitte Ihre Ansicht dazu erläutern?

Zweitens scheinen Sie das Framework von Grund auf neu zu entwickeln, ohne sich auf die Standardbibliothek zu stützen, wenn Sie sagen, dass CTrendLine die letzte Zeile mit der spracheigenen Funktion ObjectCreate erstellt.
Wann würden Sie empfehlen, die Standardbibliotheken selbst zu erweitern? Nehmen wir zum Beispiel an, ich möchte, dass alle CIndicator-Objekte der Standardbibliothek in der Lage sind zu sagen, wie oft der Preis einen Puffer in ihnen berührt hat
in den letzten X Bars. Wie würden Sie vorgehen, denn wenn Sie eine Basisklasse wie CIndicator oder CIndicatorBuffer erweitern, dann haben Sie alle abhängigen Objekte der Standardbibliothek, die von Ihrem
neuen CIndicator oder neuen CBuffer erben müssen, wie zum Beispiel CiMA. Würdest du all diese benutzerdefinierten Indikator-Klassen in deinen Ordner kopieren und ihre Vererbung auf deinen neuen CIndicatorBuffer ändern? Was passiert dann, wenn metaquotes etwas zu seinen Standard-CIndicatorBuffer- oder höheren Klassen hinzufügt?

Vielen Dank für die Einblicke.

BR

1. Vererbung des Containers.

Eine Einschränkung von MQL ist, dass man nicht mehrere Vererbungen haben kann. Daher muss man mindestens einen Tod sterben. Natürlich hast du recht, es würde auch Sinn machen, von CArrayObj zu erben, aber das würde ich nicht tun, weil der Container alle Ereignisse, die jedes CTimePrice-Objekt behandelt, z.B. Tick()->OnTick(), behandelt und an seine Kinder verteilt, während ein Array-Objekt damit nichts zu tun hat. Ein Container-Objekt, das andere Objekte enthält, die ebenfalls von der gleichen Basisklasse erben, hat einfach mehr Gemeinsamkeiten. Ein solcher Container könnte auch einen Anker haben, der auf einem Preis und einer Zeit basiert, und wenn Sie einen solchen Container verschieben, wäre es die Aufgabe des Containers, auch alle seine "Kinder" zu verschieben. Dies ist nur ein Beispiel, aber die Liste solcher Ideen ist wahrscheinlich länger als die Liste der Ideen über Array-Funktionalitäten.

Und ja, es ist auch so, dass ich tatsächlich solche Klassen geschaffen habe, die sich mit vielen Typen solcher Objekte beschäftigen und die Erfahrung, die ich inzwischen habe, sagt mir, dass es die richtige Entscheidung war, die Vererbung auf diese Weise zu handhaben.

2. Framework von Grund auf neu.

Ähnlich hier. Als ich anfing, etwas tiefer in die Standardbibliotheken einzusteigen, fand ich viele Dinge, die mir nicht gefielen. Nicht nur die schlechte Performance dieser, sondern auch mangelnde Flexibilität und eine unvollständige Architektur. Ich vermisse z.B. eine globale CMouse Klasse/Objekt sowie eine Klasse zwischen CWnd und CObject, denn CWnd Objekte sind Kinder des Diagramms ebenso wie Linien, und es gibt keine Verbindung zu solchen und keine endgültige Implementierung solcher Objekte, wie ich es oben beschrieben habe. Und es gibt kein Master-Objekt, das alle diese Diagramm-Objekte enthält, so dass es möglich ist, sie alle mit einem Befehl ein-/auszublenden, sie zu zerstören, was auch immer. CCanvas, dasselbe, eine nette Klasse, aber wo ist die Implementierung mit CWnd, die es mir erlaubt, interaktive Objekte auf Basis von Bitmaps zu erstellen, die von CWnd erben? Und so weiter.

Außerdem erlaubt die gesamte Struktur aller Standardbibliotheken keine Seitenketten, was aber notwendig ist, weil MQL keine Void-Pointer erlaubt. Ein Beispiel: Ich verwende eine Klasse namens CDragLine, die es mir erlaubt, Trendline-Objekte zu erstellen, die gezogen werden können. Wenn ein solches Trendline-Objekt mit einer Order und darüber hinaus mit einem Panel/Display was auch immer verbunden ist, brauche ich die Möglichkeit, eine solche Side-Chain zu verwenden, dass das verbundene Panel auch Informationen über Bewegungen/Veränderungen erhält, die durch Änderungen der Order verursacht werden. Umgekehrt benötige ich die Möglichkeit, den Auftrag zu verschieben und dem Panel mitzuteilen, wenn die Zeile selbst verschoben wurde. Diese Art der dreieckigen Nachrichtenübermittlung kann nicht mit der Standardbibliothek durchgeführt werden. Dies wird durch Seitenketten erreicht, d.h. alle Objekte erben von einer erweiterten Version von CObject. Diese Klasse hat die Möglichkeit, jedes andere Objekt mit einem Objekt zu verbinden und Nachrichten an ein solches verbundenes Objekt zu senden. Auf diese Weise ist ein viel komplexeres und effektiveres Messaging möglich, ohne dass man irgendeinen merkwürdigen Code braucht.

Ich kann keine Empfehlung geben, was jeder tun sollte, aber ich habe mich entschieden, 99% der Standardbibliotheken wegzulassen, die einzigen Klassen, die ich von den Originalen übrig gelassen habe, sind CCanvas (aber mit einigen Änderungen und Fehlerbehebungen, siehe Code Base) und CSymbolInfo.

--------------

Falls jemand an der Side-Chain-Funktionalität interessiert ist, hier ist der Code meiner CObject-Klasse. Wenn man das ursprüngliche CObject in Object.mqh nach jedem Update ersetzt, erhalten die meisten Teile der Standardbibliotheken die Erweiterungen dieser Side-Chain-Funktionalität. Und ganz nebenbei wird auch die Knotenverbindung implementiert - was im Original nicht der Fall ist.

Um ein solches Side-Chain-Feature hinzuzufügen, gehen Sie innerhalb der empfangenden Klasse wie folgt vor:

//--- Example for receiving class
//---

class CAnyClass : public CAnyBaseClass // of course CAnyBaseClass inherits from CObject in the end too
   {
   private:
      CWhatEver   m_object;     // embedded object
      CFurther    m_further;    // embedded object

   public:
   //+------------------------------------------------------------------+
   //|  Creation                                                        |
   //+------------------------------------------------------------------+
   CAnyClass(void)
      {
      m_classname="CAnyClass"; 

      //--- Connect side chains 
      m_object.CustomEventReceiver(PTR(this));
      m_further.CustomEventReceiver(PTR(this));
      }
   
   protected:
   //+------------------------------------------------------------------+
   //|  Custom event handler for side chain messages                    |
   //+------------------------------------------------------------------+
      virtual void      OnCustomEvent(CObject * sender, int eventid)
         {
            if (sender==PTR(m_object))
               {
               switch (eventid)
                  {
                  case 123456:
                     Print("Here we go with 123456");
                     break;
               //...
                  }
               }
            else if (sender==PTR(m_further))
               {
               //...
               } 
         }            
   };

Die sendenden Klassen CWhatEver und CFurther wissen nichts über den Empfänger, ob es einen Empfänger gibt oder nicht. Der Code ist einfach der folgende:

//---
//...

   CustomEvent(123456);

//...
//---

Hier ist der CObject-Ersatz:

//+------------------------------------------------------------------+
//|                                                       Object.mqh |
//|                                               Copyright by Doerk |
//+------------------------------------------------------------------+

#ifndef __DH_OBJECT_CLASS
#define __DH_OBJECT_CLASS

#include <stdlib.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//| Defintions                                                       |
//|                                                                  |
//+------------------------------------------------------------------+
#ifndef  PTR
   #define  PTR(object) GetPointer(object)
   #define  PTR_DELETE(object) { if (CheckPointer(object)==POINTER_DYNAMIC) delete object; }
   #define  PTR_INVALID(object) (object==NULL || CheckPointer(object)==POINTER_INVALID)
#endif   

enum ENUM_FILE_IO
   {
   FILE_IO_NONE = 0,    //--- No file interaction
   FILE_IO_BINARY = 1,  //--- Binary, OnLoad() / OnSave() events
   FILE_IO_INI = 2,     //--- Ini file, OnLoadIni() / OnSaveIni() events
   };
   
//+------------------------------------------------------------------+
//|                                                                  |
//| Class CStruct - the base of everything                           |
//|                                                                  |
//+------------------------------------------------------------------+
class CStruct
   {
   };
//+------------------------------------------------------------------+
//|                                                                  |
//| Class CObject                                                    |
//|                                                                  |
//+------------------------------------------------------------------+
class CObject : public CStruct
  {
   protected:      
      long              m_obj_id;               //--- Unique ID of each object
      string            m_classname;            //--- Name of (deriving) class
      CObject          *m_prev;                 //--- Previous item in chain
      CObject          *m_next;                 //--- Next item in chain
      CStruct          *m_struct;               //--- Additional attached struct
      CObject          *m_object;               //--- Additional attached object
      string            m_tag;                  //--- Additional tag (File operation)
   private:
      CObject          *m_eventreceiver;        //--- Object which gets custom notifications
      ENUM_FILE_IO      m_fileio;               //--- Enables/disable file input/output
      
   public:
      //+------------------------------------------------------------------+
      //| Construction                                                     |
      //+------------------------------------------------------------------+
      CObject(void) : m_fileio(FILE_IO_BINARY),
                      m_struct(NULL),
                      m_tag(NULL),
                      m_object(NULL)
         {
      //--- Set ID
            __obj_cnt++;
            m_obj_id=__obj_cnt;
      //--- Reset notified object            
            m_eventreceiver=NULL;
      //--- Connect chain            
            Prev(__obj_prev);
            if (__obj_prev!=NULL)
               __obj_prev.Next(PTR(this));
            __obj_prev=PTR(this);
            Next(NULL);
            
         } 
         
      //+------------------------------------------------------------------+
      //| Destruction                                                      |
      //+------------------------------------------------------------------+
      ~CObject(void)
         {
      //--- Reconnect chain
            if (m_prev!=NULL)
               m_prev.Next(m_next);
            if (m_next!=NULL)
               m_next.Prev(m_prev);    
            if (__obj_prev==PTR(this))
               __obj_prev=Prev();                    
         } 
      //+------------------------------------------------------------------+
      //| Chain access                                                     |
      //+------------------------------------------------------------------+
   public:      
      CObject          *Prev(void)                                      const { return(m_prev); }
      void              Prev(CObject *node)                                   { m_prev=node;    }
      CObject          *Next(void)                                      const { return(m_next); }
      void              Next(CObject *node)                                   { m_next=node;    }
      //+------------------------------------------------------------------+
      //| Custom events - allows interaction between embedded objects and  |
      //|                containers                                        |
      //+------------------------------------------------------------------+
   public:
      CObject *         CustomEventReceiver(void)                       const { return(m_eventreceiver); }
      bool              CustomEventReceiver(CObject *receiver)
         {
            if (m_eventreceiver!=NULL)
               return false;
            m_eventreceiver=receiver;
            return true;   
         }
      void              CustomEvent(int eventid=0)
         {
            if (!PTR_INVALID(m_eventreceiver))
               m_eventreceiver._CustomEvent(PTR(this), eventid);
         }      
      void              _CustomEvent(CObject * sender, int eventid)
         {
            OnCustomEvent(sender, eventid);
         }      
   protected:
      virtual void      OnCustomEvent(CObject * sender, int eventid)         
         {
         }
                                          
      //+------------------------------------------------------------------+
      //| File interaction                                                 |
      //+------------------------------------------------------------------+
   public:
      bool              Save(const int file_handle)                           { if (m_fileio==FILE_IO_NONE) return true; return(OnSave(file_handle));   }
      bool              Load(const int file_handle)                           { if (m_fileio==FILE_IO_NONE) return true; return(OnLoad(file_handle));   }
      bool              Save(CObject *fileobject)                             { if (m_fileio==FILE_IO_NONE) return true; return(OnSave(fileobject)); }
      bool              Load(CObject *fileobject)                             { if (m_fileio==FILE_IO_NONE) return true; return(OnLoad(fileobject)); }
      bool              LoadDefault(void)                                     { return (OnLoadDefault()); }
      bool              FileIO(const ENUM_FILE_IO flag)                       { m_fileio=flag; return true; }
      ENUM_FILE_IO      FileIO(void)                                          { return m_fileio; }
   protected:
      virtual bool      OnSave(const int file_handle)                         { return true; }
      virtual bool      OnLoad(const int file_handle)                         { return true; }
      virtual bool      OnSave(CObject *fileobject)                           { return true; }
      virtual bool      OnLoad(CObject *fileobject)                           { return true; }
      virtual bool      OnLoadDefault(void)                                   { return true; }
      
      //+------------------------------------------------------------------+
      //| Identification                                                   |
      //+------------------------------------------------------------------+
   public:      
      long              Id(void)                                        const { return m_obj_id;    }
      virtual int       Type(void)                                      const { return(0);      }
      string            ClassName(void)                                 const { return(m_classname); }
      string            Tag(void)                                       const { return m_tag; }
      bool              Tag(string value)                                     { m_tag=value; return true; }

      //+------------------------------------------------------------------+
      //| Comparison                                                       |
      //+------------------------------------------------------------------+
   public:      
      virtual int       Compare(const CObject *node,const int mode=0)   const { return(0);      }
      
  };
//+------------------------------------------------------------------+
long __obj_cnt=-1;
CObject * __obj_prev=NULL;
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+

#endif                  // __DH_OBJECT_CLASS
 

Vielen Dank für die Ausarbeitung und für die gemeinsame Nutzung der Seitenkette Idee.

Ehrlich gesagt, ich verstehe nicht ganz, und der Code nicht kompilieren (ich erstellt CWhatEver und CFurther als leere Klassen direkt erben die CObject Sie gepostet mit nur Konstruktor nur um die Idee zu bekommen).

Ich habe 2 Kompilierfehler erhalten, die besagen, dass CWhatEver::CWhatEver keine private Mitgliedsfunktion aufrufen kann und den gleichen Fehler für CFurther.

Jedenfalls habe ich den Begriff "Seitenkette" gegoogelt und konnte ihn nicht finden. Wenn Sie zufällig etwas schriftliches Material kennen, das ich lesen kann, wäre das großartig.

BR

 

Ja, die Klassen sind leer, deshalb lassen sie sich nicht kompilieren. Dies sind nur Platzhalter.

Seitenketten ist vielleicht nicht die offizielle Beschreibung dafür, es ist eher meine saubere MQL-Umgehung für ungültige Zeiger und/oder Mehrfachvererbung. In kurzen Worten: Es gibt Ihnen die Möglichkeit, zwischen beliebigen Klassen zu kommunizieren und ist sehr nützlich, wenn Objekte in Klassen eingebettet sind, weil Sie ihnen "sagen" können, dass die enthaltende Klasse der Empfänger ihrer eigenen Ereignisse ist. Auf diese Weise können Sie jede Art von Spaghetti-Codierung vermeiden.

Zum Beispiel, wenn Sie etwas haben wie

return OnClick();

haben, das die Überladung der letzten ableitenden Klasse zuerst aufruft, könnten Sie es erweitern zu etwas wie

return OnClick()&CustomEvent(CUSTOM_CLICK);

Auf diese Weise kann nicht nur die ableitende Klasse, die normalerweise eine

virtuelles bool OnClick()

Funktion hat, benachrichtigt werden, sondern auch die Klasse, die das Objekt enthält, kann die Klick-Benachrichtigung erhalten.

 

Meinen Sie, dass es eine Möglichkeit ist, zwischen zwei beliebigen Objekten zu kommunizieren, nicht durch übliche Nachrichtenübermittlung, die das andere Objekt kennen muss, an das sie eine Nachricht sendet, sondern durch benutzerdefinierte Ereignisse?

Diese Idee habe ich verstanden, aber was meinen Sie mit eingebetteten Objekten? In Ihrem Code von CAnyClass hatten Sie zwei private Objekte. Meinen Sie mit eingebettet, dass ihre Körper sollte auch innerhalb von decalred
CAnyClass deklariert werden oder können sie außerhalb definiert werden? Ich meine, eingebettet, wie Sie den Begriff verwenden, ist ein Objekt, das innerhalb eines anderen Objekts privat ist?

Wenn ich z. B. CWhatEver außerhalb von CAnyClass schreibe und CAnyClass über ein Ereignis informieren möchte, meinen Sie, dass ich in CWhatEver Folgendes zurückgeben werde

return OnClick()&CustomEvent(CUSTOM_CLICK); // <=== Sie meinen && anstelle von & ????

was die abgeleitete Klasse von CWhatEver wie üblich benachrichtigen wird und auch die enthaltende Klasse, die CAnyClass ist (wegen des benutzerdefinierten Ereignisses)?

Und warum ist CObject innerhalb eines #ifndef definiert?

BTW, nur neugierig, was ist der Zweck der stdlib.mqh in Ihrem CObject?

 

Von unten nach oben ...

- die stdlib, ist sie nicht sowieso in der originalen object.mqh enthalten? Ich brauche sie hier nicht, aber sie enthält CompareDouble(), die einzige zuverlässige Möglichkeit, zwei Doubles zu vergleichen

- Ich verwende #ifndef, um standardmäßig doppelte Definitionen zu vermeiden und für bedingte Kompilierung

- ja, für dreieckige Nachrichtenübermittlung

- das binäre & und die logische Version && sind das gleiche mit boolschen Ergebnissen

- mit eingebettet meine ich, wenn eine Instanz/ein Objekt einer fremden Klasse Teil einer anderen Klasse ist und beide nicht voneinander abgeleitet sind. Nehmen Sie das OnClick()-Beispiel und gehen Sie davon aus, dass das m_object das OnClick() irgendwie für interne Zwecke behandelt, z.B. wenn es sich um eine Schaltfläche oder was auch immer handelt. Wie würde der Code aussehen, wenn Sie innerhalb von CAnyClass wissen müssen, dass es einen Klick ohne dieses benutzerdefinierte Ereignis gab?

Um ehrlich zu sein, es ist keine Funktionalität, die man jeden Tag für jeden Zweck braucht, aber wenn es eine Situation gibt, in der man nicht nur die Richtung kommunizieren muss, ist es die Lösung.

Zurück zu dem ursprünglichen Thema des Threads. Die Idee war, Arrays zu verwenden, um mehrere Linien zu verwalten, die auf den Preis reagieren. Diese Linienobjekte behandeln Ereignisse, wenn sie/ihre Linien von einer Kerze gekreuzt werden und eine Aktion auslösen. Ich habe empfohlen, einen Container zu verwenden. Wenn dieser Container nun diese Aktionen zählen möchte, kann dies einfach auf diese Weise geschehen, indem der Container jedem Objekt mitteilt, dass es der Empfänger des benutzerdefinierten Ereignisses ist, z.B. mit

m_trendline[n].CustomEventReceiver(PTR(this));

während die CTrendLine-Klasse das natürlich irgendwie implementieren muss, etwa so:

return OnLineCrossed()&CustomEvent(CTRENDLINE_CROSSED);

 
Wow, wie toll , dass es eine solche Diskussion im Forum gibt. Obwohl ich zugeben muss, dass ich noch am Anfang von OOP stehe.

Leider fahre ich
für zwei Wochen in den Urlaub . DerFlieger geht in wenigen Stunden (ok, könnte schlimmer sein).

Eine Frage habe ich schon an dieser Stelle: Gibt es irgendwo eine ausführliche Dokumentation über das MQL-Rahmenwerk?


Willbur
 
Willbur:
..

Eine Frage habe ich bereits an dieser Stelle: Gibt es irgendwo eine ausführliche Dokumentation über das MQL-Rahmenwerk?

Nein :-(

Meiner Erfahrung nach ist es gut, sich mit dem "mql framework" zu beschäftigen. Aber wie Doerk schon sagte, gibt es eine Menge Probleme mit der Standardbibliothek, und meiner Meinung nach ist sie für ernsthafte und große Projekte nicht brauchbar.

 
Doerk Hilger:

Von unten nach oben ...

- die stdlib, ist sie nicht sowieso in der originalen object.mqh enthalten? Ich brauche sie hier nicht, aber sie enthält CompareDouble(), die einzige zuverlässige Möglichkeit, zwei Doubles zu vergleichen

- Ich verwende #ifndef, um standardmäßig doppelte Definitionen zu vermeiden und für bedingte Kompilierung

- ja, für dreieckige Nachrichtenübermittlung

- das binäre & und die logische Version && sind das gleiche mit boolschen Ergebnissen

- mit eingebettet meine ich, wenn eine Instanz/ein Objekt einer fremden Klasse Teil einer anderen Klasse ist und beide nicht voneinander abgeleitet sind. Nehmen Sie das OnClick()-Beispiel und gehen Sie davon aus, dass das m_object das OnClick() irgendwie für interne Zwecke behandelt, z.B. wenn es sich um eine Schaltfläche oder was auch immer handelt. Wie würde der Code aussehen, wenn Sie innerhalb von CAnyClass wissen müssen, dass es einen Klick ohne dieses benutzerdefinierte Ereignis gab?

Um ehrlich zu sein, es ist keine Funktionalität, die man jeden Tag für jeden Zweck braucht, aber wenn es eine Situation gibt, in der man nicht nur die Richtung kommunizieren muss, ist es die Lösung.

Zurück zu dem ursprünglichen Thema des Threads. Die Idee war, Arrays zu verwenden, um mehrere Linien zu verwalten, die auf den Preis reagieren. Diese Linienobjekte behandeln Ereignisse, wenn sie/ihre Linien von einer Kerze gekreuzt werden und eine Aktion auslösen. Ich habe empfohlen, einen Container zu verwenden. Wenn dieser Container nun diese Aktionen zählen möchte, kann dies einfach auf diese Weise geschehen, indem der Container jedem Objekt mitteilt, dass es der Empfänger des benutzerdefinierten Ereignisses ist, z.B. mit

m_trendline[n].CustomEventReceiver(PTR(this));

während die CTrendLine-Klasse dies natürlich irgendwie implementieren muss, etwa so:

return OnLineCrossed()&CustomEvent(CTRENDLINE_CROSSED);

stdlib dachte ich wäre nur MQL4, aber vielleicht liege ich ja falsch.
Sorry, ich habe nicht verstanden, warum das ganze CObject innerhalb von #ifndef sein muss. Was wird doppelt definiert, wenn es einfach geschrieben werden würde? Und btw, warum setzen Sie CStruct als leere Klasse über CObject?

Was die eingebettete Klasse angeht (sorry, ich bin auch Programmierer seit 25 Jahren, aber nicht OO), bezieht sich Ihr Beispiel auf eine Situation wie die folgende, zum Beispiel? Angenommen, ich bin eine CCar-Klasse, und ich habe eine CWheel-Klasse eingebettet.
Und das CWheel hat einen Eventhandler für den Mindestluftdruck oder so, und ich als Auto muss das wissen?
Wenn Sie Ähnlichkeiten zu diesem Beispiel oder anderen spezifischen finden können, denn ich bin immer noch nicht ganz da in Bezug auf die Klasse, die Ereignisse auslöst (in dem Beispiel, das Sie mit Klick gegeben haben, ist es offensichtlich die Karte) und wer sie behandelt. Und auch technisch, das Verständnis zum Beispiel diese Zeilen (ich nehme an, ihr Zweck ist es, zu zeigen, wie Container die Arbeit der Verwaltung der Trendlinien Kreuzung der Preis von einem Bar):

m_trendline[n].CustomEventReceiver(PTR(this));
können Sie klären, ob ich es richtig verstanden habe? ruft es die alle Trendlinien [1..n] in einer Schleife? wenn ja, welche Art von einem allgemeinen Ereignis könnte es sein, dass der Container gerade behandelt? es ist nicht Linie
Könnte es sich um einen neuen Balken oder eine Preisänderung handeln, die das Ereignis CTRENDLINE_CROSSED auslösen könnte? Und warum sendet es GetPointer(this) an jede Zeile?
Muss die Linie einen Callback-Container haben, und warum?
Also, wenn das der Fall ist,

return OnLineCrossed()&CustomEvent(CTRENDLINE_CROSSED);
dann ruft jede Linie ihr eigenes OnLineCrossed() auf - was eine reguläre Methode sein sollte, die nur prüft, ob der Kurs von dieser spezifischen Linie überschritten wurde,
und dann CustomEvent(CTRENDLINE_CROSSED) aufrufen - dessen Aufgabe es ist, ChartCustomEvent(..) aufzurufen, um das Ereignis CTRENLINE_CROSSED auszulösen - das in Ihrer Struktur wieder im Container behandelt wird? ist der letzte Teil das, was die dreieckige Kommunikation ausmacht, oder vermische ich hier vielleicht nur zwei verschiedene Konzepte. Der Container wird also einen CustomEvent-Handler haben, der CTRENDLINE_CROSSED behandelt?

Wenn ich das schreibe, werden einige Dinge klarer, denke ich (und der CCar kann ignoriert werden, wenn Sie möchten, und konzentrieren sich nur auf die Trendlinie), aber ich verstehe immer noch nicht, warum GetPointer(this) zu jeder Linie zu bewegen? Und auf welche Art von Ereignis zum Beispiel wird der Container den benutzerdefinierten Ereignisempfänger in jeder Zeile aufrufen, um Preisänderungen zu erkennen, und wo ist die trianguläre Kommunikation oder gilt nur das vorherige Beispiel für trianguläre nur (mit CAnyClass)?
Können Sie vielleicht das trianguläre Beispiel auf diese Trendlinie anwenden?

Ich danke Ihnen wirklich für Ihre Zeit und Geduld und Hilfe so weit, es ist überhaupt nicht offensichtlich. Ich muss sagen, Sie haben mir die Augen für das Potenzial der ereignisgesteuerten Programmierung geöffnet.