Projekt des Beraters - Seite 5

 

George Merts
Стандартный CObject - это "объект списка или сортированного массива". CMyObject - это CObject, имеющий определенный тип, и содержащий некоторое значение, данное при его создании. Этот объект мне понадобился всвязи с повсеместным приведением объектов к базовому абстрактному классу - чтобы понимать по указателю, на какой именно объект "на самом деле" указывает. Тип CMyObject - устанавливается как раз той самой функцией SetMyObjectType(). Эта функция в обязательном порядке вызывается в конструкторах любых наследников от CMyObject, чтобы назначить идентификатор класса, к которому принадлежит создаваемый объект.

Ihr Konstruktor ist offen und nicht parametrisiert:

class CTradeHistoryI: public CMyObject
{
public:
   void CTradeHistoryI() {    SetMyObjectType(MOT_TRADE_HISTORY_I); };
}

Dies bedeutet, dass ein Erbe seinen eigenen Typ festlegen kann oder nicht. Wenn Sie also vergessen, die SetMyObjectType-Methode innerhalb des Nachfolgers aufzurufen, sind Sie aufgeschmissen.

Was können Sie tun?

1. Sie sollten den Konstruktor von außerhalb der Erstellung schließen:

class CTradeHistoryI: public CMyObject
{
protected:
   void CTradeHistoryI() {    SetMyObjectType(MOT_TRADE_HISTORY_I); };
}

In diesem Fall kann nur CTradeHistoryI descendant eine Instanz erstellen, was bedeutet, dass der Typ MOT_TRADE_HISTORY_I nicht benötigt wird. Beachten Sie, dass der Typ MOT_TRADE_HISTORY_I in der Realität nie existiert, da CTradeHistoryI eine Schnittstelle ist und es keine Instanz dieses Typs geben kann. D.h. durch Schließen des Konstruktors lösen wir den Widerspruch auf - Beschreibung des Typs, der nicht existiert.

2. Lassen Sie uns die explizite Typisierungsanforderung zum Zeitpunkt der Instanzerstellung festlegen:

enum ENUM_OBJ_TYPE
{
   OBJ_HIST_DEALS_LIST,
   OBJ_HIST_ORDERS_LIST
   ...
};

class CTradeHistoryI: public CMyObject
{
private:
   ENUM_OBJ_TYPE   m_obj_type;
protected:
   CTradeHistoryI(ENUM_OBJ_TYPE obj_type)
   {
      m_obj_type = obj_type;
   }
public:
   ENUM_OBJ_TYPE ObjectType(void) const
   {
      return m_obj_type;
   }
};

class CTradeHistory : public CTradeHistoryI
{
public:
   CTradeHistory(void);
};

CTradeHistory::CTradeHistory(void) : CTradeHistory(OBJ_HIST_DEALS_LIST)
{
}

Das war's, jetzt kann sich kein Nachkomme ohne explizite Typangabe selbst erzeugen.

 
Vasiliy Sokolov:

Warum das Rad in Form von CMyObject neu erfinden, wenn es ein Standard-CObject gibt, das jeder versteht?

Ich weiß nicht, welche Vorteile Sie in MQL CObject gefunden haben. Zwei unnötige Zeiger in jedem Objekt = 16 Bytes verloren + unnötiger Overhead bei der Speicherzuweisung und Initialisierung dieser Zeiger. OOP an sich verlangsamt die Leistung, und wenn Sie solche nutzlosen Lösungen hinzufügen...
 
Alexey Navoykov:
Ich weiß nicht, was Sie in MQL's CObject Gutes gefunden haben. Zwei unnötige Zeiger in jedem Objekt = 16 Bytes verschwendet + unnötiger Overhead bei der Speicherzuweisung und Initialisierung dieser Zeiger. OOP an sich verlangsamt die Leistung, und wenn Sie solche nutzlosen Lösungen hinzufügen...

Lernen Sie zuerst OOP, dann werden wir darüber diskutieren. Die Initialisierung von m_prev, m_next findet im Allgemeinen nicht statt.

 
Vasiliy Sokolov:

Lernen Sie zuerst OOP, dann werden wir darüber diskutieren. Die Initialisierung von m_prev, m_next findet im Allgemeinen nicht statt, wenn überhaupt.

Erst nach Ihnen.

Zur Information sei gesagt, dass die Initialisierung von Zeigern in MQL immer durchgeführt wird.

 
Vasiliy Sokolov:

Ihr Konstruktor ist offen und nicht parametrisiert:

Dies bedeutet, dass ein Erbe seinen eigenen Typ festlegen kann oder nicht. Wenn Sie also vergessen, die SetMyObjectType-Methode innerhalb des Nachfolgers aufzurufen, sind Sie aufgeschmissen.

Was können Sie tun?

...

Ja, in einigen Fällen vergesse ich tatsächlich, SetMyObjectType() anzugeben - und Objekte werden standardmäßig mit dem Typ CMyObject erstellt.

Und der Lösungsweg ist ein guter.

Vorschläge werden angenommen.

Der geschützte Konstruktor gefällt mir allerdings nicht.

 
George Merts:

Ja, in der Tat, in einigen Fällen vergesse ich, SetMyObjectType() anzugeben - und Objekte werden standardmäßig mit dem Typ CMyObject erstellt.

Und der Lösungsweg ist ein guter.

Vorschläge werden angenommen.

Obwohl ich den schützenden Konstruktor nicht mag.

Ein geschützter Konstruktor erschwert das Leben nur für diejenigen Klassen, die direkt von einem Elternteil mit einem solchen Konstruktor geerbt werden. Aber auf der Benutzerebene können Sie abgeleitete Objekte bedenkenlos und frei erstellen.

Daher sollten die Unannehmlichkeiten nicht beachtet werden.

Und es gibt keine anderen Möglichkeiten in MQL, weil es kein System zur Typüberprüfung gibt, oder besser gesagt, es existiert nur in einer unterentwickelten Form, so dass wir den Typ schützen müssen, indem wir einen Konstruktor verstecken.

 
Alexey Navoykov:
Ich weiß nicht, welche Vorteile Sie in MQL's CObject gefunden haben. Zwei unnötige Zeiger in jedem Objekt = 16 Bytes verloren + unnötiger Overhead bei der Speicherzuweisung und Initialisierung dieser Zeiger. OOP an sich verlangsamt die Leistung, und wenn man dann noch solche nutzlosen Lösungen hinzufügt...

Warum "nutzlos"? Der Overhead ist meiner Meinung nach sehr gering, und es ist offensichtlich die Bequemlichkeit wert, die CObject beim Organisieren von Listen und sortierten Arrays bietet.

Wenn wir Mikrosekunden und Bytes jagen müssen, dann ist es natürlich sinnvoll, darüber nachzudenken, ob nicht gerade diese "verlorenen Bytes" zu viele Ressourcen beanspruchen. Aber wie meine Praxis zeigt, ist die Bequemlichkeit beim Schreiben und Warten von Code viel wichtiger.

Übrigens habe ich mich kürzlich mit der Code-Optimierung beschäftigt - meine Expert Advisors waren im Tester irgendwie zu langsam. Die langsamste Funktion war die Datenaktualisierung. Ich habe also versucht, den Aufruf dieser Aktualisierung in jeder Hinsicht zu verringern. Seit kurzem ist es jedoch möglich, im Tester ein Codeprofil zu erstellen. Und zu meiner großen Überraschung sah ich, dass die meiste Zeit meines Expert Advisors auf die Funktion der Abfrage des Terminal-Status verwendet wird (die ich (fast) nicht brauchte) (sie wurde bei jeder Aktualisierung durchgeführt, und wurde einfach "gleichzeitig" mit dem Rest gemacht). Und vor allem - verschwendet auf die Funktion, die den freien Speicher anfordert. Eine kleine Änderung im Code, so dass der Terminalstatus nur einmal beim Start und dann bei Auffrischungen abgefragt wird - nur wenn explizit darauf hingewiesen wird - beschleunigte die Tests um mehr als das Dreifache!

Der "unnötige Overhead" geht also vielleicht gar nicht dort verloren, wo wir ihn suchen.

 
George Merts:

Der "unnötige Overhead" geht also vielleicht gar nicht dort verloren, wo wir ihn suchen.

Diskutieren Sie nicht mit ihm. Sein einziges Ziel ist es, zu schimpfen. Leuten wie ihm werden Sie nie etwas beweisen können. Die beste Strategie im Umgang mit solchen Personen ist das völlige Ignorieren.
 
George Merts:

Warum "nutzlos"? Der Overhead ist meiner Meinung nach sehr gering, und es ist eindeutig die Bequemlichkeit wert, die CObject beim Organisieren von Listen und sortierten Arrays bietet.

Diese "Annehmlichkeiten" werden über das Ziel hinaus geschossen. Welche Art von Liste verändert etwas an Ihren Objekten? Im Grunde genommen stellt sich heraus, dass man keine konstanten Objekte in eine Liste aufnehmen kann. Oder stellen Sie sich Ihr Objekt in einer solchen Liste vor, Sie senden es an eine Funktion, die es ebenfalls in ihre Liste aufnimmt, und dann erhalten Sie Ihr Objekt mit geändertem prev und next zurück, und das Spiel beginnt ...

In der zivilisierten Welt werden die Listen durch zusätzliche Node-Objekte implementiert, die die benötigten Zeiger speichern. Und die Benutzerobjekte selbst zu berühren ist unsinnig. Es geht also nicht nur um den Overhead, sondern um die grundsätzliche Unrichtigkeit des Ganzen. Die Entwickler haben einfach schnell etwas zusammengeschustert, und Sie sind glücklich, als ob es so sein sollte.

 
Alexey Navoykov:

Diese "Annehmlichkeiten" werden an einem Ort umgesetzt. Was für eine Liste ist es, die etwas an Ihren Objekten verändert? Im Grunde genommen kann man keine konstanten Objekte in eine Liste aufnehmen. Oder stellen Sie sich die Situation vor, dass Sie Ihr Objekt in einer solchen Liste an eine Funktion senden, die es ebenfalls in ihre Liste aufnimmt, und dann erhalten Sie Ihr Objekt mit geändertem prev und next zurück, und das Spiel beginnt ...

In der zivilisierten Welt werden die Listen durch zusätzliche Node-Objekte implementiert, die die benötigten Zeiger speichern. Und die Benutzerobjekte selbst zu berühren ist unsinnig. Es geht also nicht nur um den Overhead, sondern um die grundsätzliche Unrichtigkeit des Ganzen. Die Entwickler haben einfach kurzfristig etwas zusammengeschustert, und Sie freuen sich, als ob es so sein müsste.

Nun, ja, man kann keine konstanten Objekte in eine Liste einfügen.

Ich verwende jedoch ständig die CObject-Funktionalität, und keiner meiner Kritiker hat etwas vorgeschlagen, das auch nur annähernd mit den Objekten der Arrays und Listen der Standardbibliothek vergleichbar ist.

Alle schreien: "So sollte es gemacht werden". Aber wenn man etwas vorschlägt, ist plötzlich nichts mehr da.

Selbst diejenigen Teilnehmer, die tatsächlich andere Softwarelösungen anbieten, bieten keinen Ersatz für das CObject an - sie verwenden es häufiger überhaupt nicht, nutzen seine Funktionen seltener und achten nicht auf die "Implementierung an einem Ort", was bedeutet, dass die Implementierung recht gut ist.

Wenn es schlecht wäre, hätten sie schon längst einen Ersatz angeboten.