Projet du conseiller - page 5

 

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

Votre constructeur est ouvert et non paramétré:

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

Cela signifie qu'un héritier peut ou non définir son propre type. Ainsi, si vous oubliez d'appeler la méthode SetMyObjectType dans le descendant, vous êtes fichu.

Ce que vous pouvez faire ?

1. Vous devez fermer le constructeur depuis l'extérieur de la création :

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

Dans ce cas, seul le descendant de CTradeHistoryI pourra créer une instance, ce qui signifie qu'il n'y aura pas besoin du type MOT_TRADE_HISTORY_I. Notez que le type MOT_TRADE_HISTORY_I n'existe jamais dans la réalité, car CTradeHistoryI est une interface, et il ne peut y avoir aucune instance de ce type. C'est-à-dire qu'en fermant le constructeur nous résolvons la contradiction - description du type qui n'existe pas.

2. Définissons l'exigence de typage explicite au moment de la création de l'instance :

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

C'est tout, maintenant aucun descendant ne peut se créer lui-même sans spécification explicite du type.

 
Vasiliy Sokolov:

Pourquoi réinventer la roue sous la forme de CMyObject, alors qu'il existe un CObject standard que tout le monde comprend ?

Je ne sais pas ce que vous avez trouvé de bon dans MQL CObject. Deux pointeurs inutiles entassés dans chaque objet = 16 octets perdus + surcharge inutile sur l'allocation de mémoire et l'initialisation de ces pointeurs. La POO en elle-même ralentit les performances, et si vous ajoutez des solutions aussi inutiles...
 
Alexey Navoykov:
Je ne sais pas ce que vous avez trouvé de bon dans le CObject de MQL. Deux pointeurs inutiles entassés dans chaque objet = 16 octets gaspillés + surcharge inutile sur l'allocation de mémoire et l'initialisation de ces pointeurs. La POO en elle-même ralentit les performances, et si vous ajoutez des solutions aussi inutiles...

Apprenez d'abord la POO, puis nous en discuterons. L'initialisation de m_prev, m_next n'a pas lieu dans le cas général.

 
Vasiliy Sokolov:

Apprenez d'abord la POO, puis nous en discuterons. L'initialisation de m_prev, m_next en général ne se produit pas si quoi que ce soit.

Seulement après toi.

Ainsi, à titre d'information, l'initialisation des pointeurs dans MQL est toujours effectuée.

 
Vasiliy Sokolov:

Votre constructeur est ouvert et non paramétré:

Cela signifie qu'un héritier peut ou non définir son propre type. Ainsi, si vous oubliez d'appeler la méthode SetMyObjectType dans le descendant, vous êtes fichu.

Que pouvez-vous faire ?

...

Oui, en effet, dans certains cas, j'oublie de spécifier SetMyObjectType() - et les objets sont créés avec le type CMyObject par défaut.

Et la méthode de solution est bonne.

Les suggestions sont acceptées.

Je n'aime pas le constructeur protégé cependant.

 
George Merts:

Oui, en effet, dans certains cas, j'oublie de spécifier SetMyObjectType() - et les objets sont créés avec le type CMyObject par défaut.

Et la méthode de solution est bonne.

Suggestions acceptées.

Bien que je n'aime pas le constructeur de protection.

Le constructeur protégé ne complique la vie que pour les classes qui sont directement héritées d'un parent avec un tel constructeur. Mais au niveau de l'utilisateur, vous pouvez créer des objets dérivés sans hésitation et librement.

Par conséquent, le désagrément ne devrait pas être observé.

Et il n'y a pas d'autres options dans MQL, parce qu'il n'y a pas de système de vérification de type, ou plutôt, il existe mais sous une forme sous-développée, donc, nous devons protéger le type en cachant un constructeur.

 
Alexey Navoykov:
Je ne sais pas ce que vous avez trouvé de bon dans le CObject de MQL. Deux pointeurs inutiles entassés dans chaque objet = 16 octets perdus + surcharge inutile sur l'allocation de mémoire et l'initialisation de ces pointeurs. La POO en elle-même ralentit les performances, et quand on y ajoute des solutions aussi inutiles...

Pourquoi "inutile" ? La surcharge est, à mon avis, très faible, et elle vaut évidemment la commodité que CObject apporte lors de l'organisation de listes et de tableaux triés.

Si nous devons courir après les microsecondes et les octets, il est bien sûr logique de se demander si ces mêmes "octets perdus" ne représentent pas trop de ressources. Mais comme le montre ma pratique, la commodité de l'écriture et de la maintenance du code est bien plus importante.

À propos, j'ai récemment participé à l'optimisation du code - mes conseillers experts étaient en quelque sorte trop lents dans le testeur. La fonction la plus lente était le rafraîchissement des données. J'ai donc essayé de diminuer l'appel de ce rafraîchissement dans tous les sens. Mais, récemment, il est devenu possible de profiler du code dans le testeur. Et à ma grande surprise, j'ai vu que la plupart du temps de mon Expert Advisor est passé sur la fonction de demande de l'état terminal (dont je n'avais (presque) pas besoin) (elle était exécutée à chaque rafraîchissement, et elle était juste faite "en même temps" que le reste). Et surtout - gaspillé sur la fonction qui demande la mémoire libre. Un léger changement dans le code, afin que l'état du terminal ne soit interrogé qu'une seule fois au démarrage et ensuite lors des rafraîchissements - uniquement lorsque cela est explicitement indiqué - a accéléré les tests par plus de trois fois !

Ainsi, les "frais généraux inutiles" ne sont peut-être pas perdus là où nous les cherchons.

 
George Merts:

Il se peut donc que les "frais généraux inutiles" ne soient pas du tout perdus là où nous les cherchons.

Ne discutez pas avec lui. Son seul but est de fulminer. Vous ne prouverez jamais rien à des gens comme lui. La meilleure stratégie pour traiter avec de tels personnages est de les ignorer totalement.
 
George Merts:

Pourquoi "inutile" ? La surcharge est, à mon avis, très faible, et elle vaut clairement la commodité que CObject fournit dans l'organisation des listes et des tableaux triés.

Ces "commodités" sont mises en œuvre de manière excessive. Quel genre de liste change quelque chose dans vos objets ? En fait, il s'avère que l'on ne peut pas mettre des objets constants dans une liste. Ou bien imaginez votre objet dans une telle liste, vous l'envoyez à une fonction, qui le met aussi dans sa liste, et ensuite vous récupérez votre objet avec prev et next modifiés, et le jeu commence ....

Dans le monde civilisé, les listes sont implémentées par des objets auxiliaires Node, qui stockent les pointeurs nécessaires. Et toucher les objets utilisateurs eux-mêmes est un non-sens. Il ne s'agit donc pas seulement des frais généraux, mais de l'incorrection fondamentale de tout cela. Les développeurs ont juste bricolé quelque chose à la hâte et vous êtes heureux comme si cela devait être ainsi.

 
Alexey Navoykov:

Ces "commodités" sont mises en œuvre en un seul endroit. Quelle est cette liste qui change quelque chose à vos objets ? En fait, vous ne pouvez pas mettre des objets constants dans une liste. Ou bien imaginez la situation où vous envoyez votre objet dans une telle liste à une fonction, qui le met aussi dans sa liste, et où vous récupérez votre objet avec des prev et next modifiés, et le jeu commence...

Dans le monde civilisé, les listes sont implémentées par des objets auxiliaires Node, qui stockent les pointeurs nécessaires. Et toucher les objets utilisateurs eux-mêmes est un non-sens. Il ne s'agit donc pas seulement des frais généraux, mais de l'incorrection fondamentale de tout cela. Les développeurs ont juste bricolé quelque chose au pied levé et vous êtes heureux comme si cela devait être ainsi.

Eh bien, oui, vous ne pouvez pas mettre des objets constants dans une liste.

Cependant, j'utilise constamment la fonctionnalité CObject et aucune de mes critiques n'a suggéré quoi que ce soit de similaire aux objets des tableaux et des listes de la bibliothèque standard.

"La façon dont les choses devraient être faites", c'est ce que tout le monde crie. Mais pour suggérer quelque chose, tout d'un coup, il n'y a rien.

Même les participants qui offrent effectivement différentes solutions logicielles ne proposent pas de remplacement pour le CObject - le plus souvent ils ne l'utilisent pas du tout, moins souvent ils utilisent ses fonctionnalités, sans prêter attention à la "mise en œuvre en un seul endroit", ce qui signifie que la mise en œuvre est assez bonne.

Si c'était mauvais, ils auraient proposé un remplacement depuis longtemps.

Raison: