Progetto del consigliere - pagina 5

 

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

Il vostro costruttore è aperto e non parametrizzato:

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

Questo significa che un erede può o non può impostare il proprio tipo. Quindi se vi dimenticate di chiamare il metodo SetMyObjectType all'interno del discendente, siete fregati.

Cosa si può fare?

1. Dovreste chiudere il costruttore dall'esterno della creazione:

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

In questo caso solo il discendente CTradeHistoryI potrà creare un'istanza, il che significa che non ci sarà bisogno del tipo MOT_TRADE_HISTORY_I. Si noti che il tipo MOT_TRADE_HISTORY_I non esiste mai nella realtà, perché CTradeHistoryI è un'interfaccia e non può esistere un'istanza di questo tipo. Cioè, chiudendo il costruttore si risolve la contraddizione - descrizione del tipo che non esiste.

2. Impostiamo il requisito di tipizzazione esplicita al momento della creazione dell'istanza:

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)
{
}

Questo è tutto, ora nessun discendente può creare se stesso senza una specificazione esplicita del tipo.

 
Vasiliy Sokolov:

Perché reinventare la ruota sotto forma di CMyObject, quando c'è un CObject standard che tutti capiscono?

Non so cosa ci sia di buono in MQL CObject. Due puntatori inutili stipati in ogni oggetto = 16 byte persi + overhead inutile sull'allocazione della memoria e l'inizializzazione di questi puntatori. L'OOP di per sé rallenta le prestazioni, e se si aggiungono queste soluzioni inutili...
 
Alexey Navoykov:
Non so cosa avete trovato di buono nel CObject di MQL. Due puntatori inutili stipati in ogni oggetto = 16 byte sprecati + overhead inutile sull'allocazione della memoria e l'inizializzazione di questi puntatori. L'OOP di per sé rallenta le prestazioni, e se si aggiungono queste soluzioni inutili...

Impara prima l'OOP, poi ne parleremo. L'inizializzazione di m_prev, m_next non avviene nel caso generale.

 
Vasiliy Sokolov:

Impara prima l'OOP, poi ne parleremo. L'inizializzazione di m_prev, m_next in generale non avviene se non altro.

Solo dopo di te.

E così, a titolo informativo, l'inizializzazione dei puntatori in MQL viene sempre eseguita.

 
Vasiliy Sokolov:

Il vostro costruttore è aperto e non parametrizzato:

Questo significa che un erede può o non può impostare il proprio tipo. Quindi se vi dimenticate di chiamare il metodo SetMyObjectType all'interno del discendente, siete fregati.

Cosa si può fare?

...

Sì, infatti in alcuni casi mi dimentico di specificare SetMyObjectType() - e gli oggetti vengono creati con il tipo CMyObject per default.

E il metodo di soluzione è un buon metodo.

Si accettano suggerimenti.

Non mi piace però il costruttore protetto.

 
George Merts:

Sì, in effetti, in alcuni casi mi dimentico di specificare SetMyObjectType() - e gli oggetti vengono creati con il tipo CMyObject di default.

E il metodo di soluzione è un buon metodo.

Suggerimenti accettati.

Anche se non mi piace il costruttore protettivo.

Il costruttore protetto complica la vita solo a quelle classi che sono ereditate direttamente da un genitore con tale costruttore. Ma a livello di utente, si possono creare oggetti derivati senza esitazione e liberamente.

Pertanto, l'inconveniente non dovrebbe essere osservato.

E non ci sono altre opzioni in MQL, perché non c'è un sistema di controllo dei tipi, o meglio, esiste ma in una forma poco sviluppata, quindi, dobbiamo proteggere il tipo nascondendo un costruttore.

 
Alexey Navoykov:
Non so cosa ci sia di buono nel CObject di MQL. Due puntatori inutili stipati in ogni oggetto = 16 byte persi + overhead inutile sull'allocazione della memoria e l'inizializzazione di questi puntatori. L'OOP di per sé rallenta le prestazioni, e quando ci aggiungi queste soluzioni inutili...

Perché "inutile"? L'overhead è, a mio parere, molto piccolo, e vale ovviamente la comodità che CObject dà quando si organizzano liste e array ordinati.

Se dobbiamo rincorrere i microsecondi e i byte, allora, naturalmente, ha senso pensare se questi stessi "byte persi" non rappresentino troppe risorse. Ma come dimostra la mia pratica, la comodità della scrittura e della manutenzione del codice è molto più importante.

A proposito, sono stato recentemente coinvolto nell'ottimizzazione del codice - i miei Expert Advisors erano in qualche modo troppo lenti nel tester. La funzione più lenta era nell'aggiornamento dei dati. Così ho cercato di diminuire la chiamata di questo refresh in tutti i modi. Ma, recentemente è diventato possibile profilare il codice nel tester. E con mia grande sorpresa, ho visto che la maggior parte del tempo del mio Expert Advisor è speso nella funzione di richiesta dello stato del terminale (di cui non avevo bisogno (quasi)) (veniva eseguita ad ogni refresh, ed era solo fatta "allo stesso tempo" con il resto). E soprattutto - sprecato per la funzione che richiede la memoria libera. Un piccolo cambiamento nel codice, in modo che lo stato del terminale sia interrogato solo una volta all'avvio e poi al refresh - solo quando esplicitamente indicato - ha accelerato i test di più di tre volte!

Quindi il "sovraccarico inutile" potrebbe essere perso non proprio dove lo stiamo cercando.

 
George Merts:

Quindi il 'sovraccarico inutile' potrebbe non essere affatto perso dove lo stiamo cercando.

Non discutere con lui. Il suo unico obiettivo è farneticare. Non dimostrerete mai nulla a persone come lui. La migliore strategia per trattare con questi personaggi è l'ignoranza totale.
 
George Merts:

Perché "inutile"? L'overhead è, a mio parere, molto piccolo, e vale chiaramente la comodità che CObject fornisce nell'organizzare liste e array ordinati.

Queste "comodità" sono implementate sopra le righe. Che tipo di lista cambia qualcosa nei vostri oggetti? In sostanza, si scopre che non si possono mettere oggetti costanti in una lista. Oppure immaginate il vostro oggetto in una tale lista, lo inviate a una funzione, che lo mette anche nella sua lista, e poi riavrete il vostro oggetto con prev e next modificati, e il gioco comincia...

Nel mondo civilizzato le liste sono implementate attraverso oggetti Node ausiliari, che memorizzano i puntatori necessari. E toccare gli stessi oggetti utente non ha senso. Quindi non è solo l'overhead, ma la fondamentale scorrettezza di tutto ciò. Gli sviluppatori hanno appena messo insieme qualcosa di veloce, e voi siete felici come se dovesse essere così.

 
Alexey Navoykov:

Queste "comodità" sono implementate attraverso un unico luogo. Che tipo di lista è quella che cambia qualcosa nei tuoi oggetti? In sostanza, non si possono mettere oggetti costanti in una lista. Oppure immaginate la situazione, quando inviate il vostro oggetto in una tale lista a una funzione, che lo mette anche nella sua lista, e poi ricevete indietro il vostro oggetto con prev e next modificati, e il gioco comincia...

Nel mondo civilizzato le liste sono implementate attraverso oggetti Node ausiliari, che memorizzano i puntatori necessari. E toccare gli stessi oggetti utente non ha senso. Quindi non è solo l'overhead, ma la fondamentale scorrettezza di tutto ciò. Gli sviluppatori hanno appena messo insieme qualcosa con poco preavviso e voi siete felici come se dovesse essere così.

Beh, sì, non si possono mettere oggetti costanti in una lista.

Tuttavia, uso costantemente la funzionalità CObject e nessuno dei miei critici ha suggerito qualcosa anche solo simile agli oggetti degli array e delle liste della Libreria Standard.

"Il modo in cui le cose dovrebbero essere fatte" è il grido di tutti. Ma per suggerire qualcosa, all'improvviso, non c'è niente.

Anche quei partecipanti che offrono effettivamente diverse soluzioni software, non offrono un sostituto per il CObject - più spesso non lo usano affatto, meno spesso usano le sue funzionalità, non prestando attenzione all'"implementazione in un posto", il che significa che l'implementazione è abbastanza buona.

Se fosse stato brutto, avrebbero offerto una sostituzione molto tempo fa.