Questions sur la POO (programmation orientée objet) - page 6

 
C-4:
Les pointeurs sont indispensables pour les conversions d'objets complexes où une identification dynamique du type est nécessaire.

Vasily, un exemple, s'il te plaît !

Je ne connais qu'un seul cas où vous devez allouer de la mémoire et où vous avez besoin d'un pointeur sur celle-ci.

Je suis sûr que vous pouvez presque toujours vous en passer. Il est souhaitable de ne pas utiliser la gestion manuelle de la mémoire. Il existe toujours une bibliothèque standard qui gère déjà ces questions.

 
Integer:


Un principe s'applique partout : tout doit être fait aussi simplement que possible. Il n'est pas nécessaire d'aller dans le feu de l'action juste pour être dans le feu de l'action. Si un problème peut être résolu simplement, il doit être résolu simplement.


Exactement. Et c'est là qu'il est important de concevoir la classe correctement. Et pour ce faire, il est important de prévoir quelles seront les classes suivantes (descendants).

En général, la classe de base doit avoir une fonctionnalité minimale, mais il est souhaitable de créer un grand nombre de méthodes virtuelles qui définissent le vecteur d'utilisation de la classe.

Dans le cas de MQL - probablement le contraire - plus de fonctionnalités dans la classe de base, comme dans VOLDEMAR. Mais sans fanatisme.


Il existe des propriétés de symboles commerciaux (POINT, NIVEAU D'ARRÊT, etc.). MODE_XXX pour MarketInfo() ). Nous ferions mieux de les mettre dans la classe cSymbol, par exemple.


Il existe des propriétés de l'ordre (prix d'ouverture, type, lot, etc.). OrdreXXX() ). Il serait préférable de les placer dans une classe cOrder distincte, par exemple.

Si nous nous souvenons que la commande peut être clôturée en plusieurs parties, nous devons également affecter le champ BaseLot à la classe (afin de savoir quelle partie du lot a déjà été clôturée) et ainsi de suite.


Il y a (pour moi) un calendrier - des périodes spécifiées (par jour) où l'on peut ouvrir et fermer des ordres, des périodes où l'on ne fait que fermer (trailing si on a déjà atteint le seuil de rentabilité) et la période où l'on ne travaille pas du tout et où l'on ferme tous les ordres ouverts et où l'on supprime les ordres non ouverts.

N'oubliez pas les écarts et le fait que dans la dernière heure de négociation, de nombreuses sociétés de courtage (si ce n'est toutes) peuvent modifier les conditions de négociation et que de nombreuses sociétés de courtage ont une pause dans les métaux de négociation chaque jour de négociation.


Et enfin, il y a l'EA - un certain algorithme qui fonctionne avec un certain symbole, selon un certain calendrier, avec une certaine liste de "ses" ordres et avec ses propres données de calcul.

Nous pouvons créer une classe cExpert, qui contiendra un objet de la classe cSymbol et un tableau d'objets de la classe cOrder. Ce cExpert de base contiendra des fonctions de mise à jour des propriétés des objets cOrder, des fonctions de traitement des commandes, de traitement des erreurs, de statistiques, etc.

Personnellement, je trouve utile de calculer le lot en %% de AccountFreeMargin(), de générer un magik unique pour chaque ordre (plus facile de mettre un ordre inverse à un ordre spécifique), la fonction de placer un ordre inverse, etc.

Et c'est de là que cExpert pourrait descendre avec des ensembles uniques de données et de fonctions supplémentaires qui décideraient de ce qu'il faut faire sur le marché (ordres d'ouverture/de fermeture).

C'est-à-dire mettre en œuvre des stratégies commerciales. Et ce sera ce que nous appelons un "EA de stratégie XXX".


Mais TOUTES les fonctionnalités de base seront dans la classe de base cExpert. Les classes enfant contiendront les algorithmes des stratégies de trading.

Peut-être que quelqu'un ajoutera un traitement avancé des erreurs ou des statistiques avancées sur les échanges (s'il n'y a pas de code source et que cela ne peut pas être intégré dans le cExpert de base).

Veuillez noter que nous prenons notre temps pour créer une classe qui simplifiera l'écriture des EA. En fait, il s'agit d'un modèle de conseiller expert. Structurellement complète et non brossée (toutes les données nécessaires se trouvent au même endroit avec le code).


Quant à la prétendue "redondance" des fonctions wrapper par rapport à openorders(), je suis personnellement favorable à ces wrappers (surtout s'ils ont des fonctionnalités supplémentaires, et ne se contentent pas d'appeler la fonction de base).

Par exemple, si dans un appel de wrapper SL et TP sont spécifiés en points et que nous devons les convertir en chiffres absolus, et de plus ajouter ou soustraire selon le type d'ordre (bien que dans ce cas aussi ces conversions puissent être placées dans operorders()).

Personnellement, je trouve plus facile de comprendre le code appelant BuyStop(...) et de vérifier une fois que BuyStop() fait tout correctement que d'analyser les paramètres de OrderSend() pour vérifier l'exactitude des paramètres à chaque fois.

PS : C'était beaucoup de travail, y compris les week-ends. Merci à Pavlick et mql5 pour les codes d'exemple.

Jetez un coup d'œil à ces exemples et demandez-vous s'il est vraiment nécessaire de créer une hiérarchie de classes dans le domaine des tâches de programmation, qui sont écrites en MQL.

Avez-vous vraiment besoin de toute une famille de cours basés sur une base (tous ces "triangles", "carrés", etc.) ?

Et une fois de plus, les mots d'or d'Integer: Ne va pas dans le fourré juste pour être dans le fourré.

Oh. Soit je n'ai pas remarqué, soit la section de documentation avec des exemples est apparue récemment.

 
Zhunko:

Je ne connais qu'un seul cas où vous devez allouer de la mémoire et où vous avez besoin d'un pointeur sur celle-ci.

Je suis sûr que vous pouvez presque toujours vous en passer. Il est conseillé de ne pas utiliser la gestion manuelle de la mémoire. Il existe toujours une bibliothèque standard qui a déjà résolu ces problèmes.


Voici probablement de quoi il s'agit.


Supposons qu'il y ait une classe cFather, elle possède une méthode int GetData() qui renvoie 3. Et la méthode PrintData(), qui produit ce qu'elle obtient de GetData().

Il y a son descendant cChild qui a surchargé GetData() qui renvoie maintenant 5.

Si nous déclarons un objet de type TestObject de cFather, alors TestObject.GetData() retournera toujours 3.

Si nous déclarons cFather* TestObject=new cChild1, alors TestObject.GetData() renverra 5, même s'il semble être cFather.

Elle est nécessaire pour que le code écrit maintenant puisse appeler la méthode GetData() sur n'importe quel descendant de la classe cFather, même si celle-ci (la classe descendante) n'existe pas encore.

C'est-à-dire que si la classe cChild2 apparaît alors, avec laquelle GetData() renverra 7, alors après cFather* Test2=new cChild2 function Test2.PrintData() commencera à sortir 7.

S'il existe une fonction qui attend un paramètre "référence à l'objet de classe cFather" et l'utilise GetData(), elle obtiendra des données correctes pour tout descendant de cFather.

La liaison des méthodes se produit lorsque new est appelé. Si elle n'est pas référencée, alors la liaison sera dure, c'est-à-dire que les méthodes de la classe déclarée seront appelées.

Voir ici et ici

 
EverAlex:

Il semble que c'est ce dont il s'agit.

...

Il existe un opérateur ": :" qui vous permet d'accéder à n'importe quelle méthode dans toute la chaîne des classes de base et dérivées sans allouer de mémoire ou de pointeur.
 
C-4:


Votre cours est redondant à 90%. Seules deux fonctions font le travail principal, ce sont les openorders et tip Pourquoi utiliser Sel, Buy SelStop, etc., alors qu'en fait elles appellent toutes Openorders ? De plus, le type d'ordre est passé en tant que int, donc il n'est pas protégé. Au lieu de int, vous devriez utiliser votre propre énumération ou le standard ENUM_ORDER_TYPE. Et en général, il vaut mieux ne jamais utiliser les nombres magiques "1", "2" etc., seulement des énumérations. Cela vous empêchera d'envoyer la valeur d'ordre gauche à la fonction. La fonction Openorders elle-même est trop importante. De toute évidence, il se compose de deux blocs, celui de la conclusion d'un accord et celui de la vérification des conditions. Chacun d'entre eux devrait être une fonction privée distincte.

C'est un bon début, mais nous avons encore beaucoup à apprendre. La fonction de pointe serait mieux réécrite comme suit :

C'est pratique pour moi de voir visuellement quel type d'ordre je passe lorsque j'appelle la méthode...

À propos de la comparaison, décrivez en détail pourquoi il n'est pas recommandé de comparer double avec 0 ?

 
C-4:
Les pointeurs sont indispensables pour les conversions d'objets complexes où une identification dynamique du type est nécessaire.

La présence d'une identification dynamique des types indique généralement l'architecture de béquille d'un projet.
 
si une classe est déclarée globalement dans une EA (Class c ;), les états des objets internes de la classe modifiés lors d'un tick seront-ils sauvegardés lors du prochain tick ?
 
EverAlex:

On dirait que c'est de ça qu'il s'agit.


Supposons que nous ayons la classe cFather; elle possède la méthode int GetData() qui renvoie 3. Et la méthode PrintData(), qui produit ce qu'elle obtient de GetData().

Il y a son descendant cChild, qui a surchargé GetData(), qui renvoie maintenant 5.

Si nous déclarons un objet de type TestObject de cFather, alors TestObject.GetData() retournera toujours 3.

Si nous déclarons cFather* TestObject=new cChild1, alors TestObject.GetData() renverra 5, même s'il semble être cFather.

Elle est nécessaire pour que le code écrit maintenant puisse appeler la méthode GetData() sur n'importe quel descendant de la classe cFather, même si celle-ci (la classe descendante) n'existe pas encore.

C'est-à-dire que si la classe cChild2 apparaît alors, avec laquelle GetData() renverra 7, alors après cFather* Test2=new cChild2 function Test2.PrintData() commencera à sortir 7.

S'il existe une fonction qui attend un paramètre "référence à l'objet de classe cFather" et l'utilise GetData(), elle obtiendra des données correctes pour tout descendant de cFather.

La liaison des méthodes se produit lorsque new est appelé. Si elle n'est pas référencée, alors la liaison sera dure, c'est-à-dire que les méthodes de la classe déclarée seront appelées.

Voir ici et ici

class cFather
{
public:
    int GetData() {return 3;}
};

class cChild : public cFather
{
public:
    int GetData() {return 5;}
};
    
int f(cFather *p) {return p->GetData();}
    
int main()
{
    cChild obj;
    f(&obj);                // вернет 3
    obj.cFather::GetData(); // вернет 3
    
    return 0;
}
 
Pavlick:


Peut-être ai-je écrit l'exemple pour rien. Cela ne fonctionne pas en MKL :

cChild obj;
f(&obj);                // вернет 3
obj.cFather::GetData(); // вернет 3

H.k., pas des pointeurs, mais des rires sur un bâton.

P.S : écrire en dlls, c'est une chance d'apprendre une langue normale.

 
Pavlick:


Peut-être ai-je écrit l'exemple pour rien. Cela ne fonctionne pas en MKL :

H.k., pas des pointeurs, mais des rires sur un bâton.

P.S : écrire en dlls, c'est une chance d'apprendre une langue normale.


class cFather
  {
public:
   int GetData() {return 3;}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class cChild : public cFather
  {
public:
   int GetData() {return 5;}
  };

int f(cFather *p) {return p.GetData();}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnStart()
  {
   cChild obj,*ptr=GetPointer(obj);
   f(ptr);                     // вернет 3
   ((cFather *)ptr).GetData(); // вернет 3

   return 0;
  }
Raison: