Pointeurs d'Objets

MQL5 permet la création dynamique d'objets de type complexe. Ceci est fait en utilisant l'opérateur 'new'qui renvoie un descripteur de l'objet créé. La taille du descripteur est de 8 octets. Syntaxiquement, les descripteurs d'objets dans MQL5 sont similaires aux pointeurs C++.

Exemple :

MyObject* hobject= new MyObject();

Contrairement au C++, la variable "hobject" de l'exemple ci-dessus n'est pas un pointeur vers la mémoire, mais un descripteur d'objet. De plus, en MQL5, tous les objets en paramètres de fonction doivent être passés par référence. Les exemples ci-dessous montrent le passage d'objets en paramètres de fonction :

class Foo
  {
public:
   string            m_name;
   int               m_id;
   static int        s_counter;
   //--- constructors and destructors
                     Foo(void){Setup("noname");};
                     Foo(string name){Setup(name);};
                    ~Foo(void){};
   //--- initialise l'objet Foo
   void              Setup(string name)
     {
      m_name=name;
      s_counter++;
      m_id=s_counter;
     }
  };
int Foo::s_counter=0;
//+------------------------------------------------------------------+
//| Fonction de démarrage du programme                               |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- déclare l'objet comme une variable, avec la création automatique
   Foo foo1;
//--- variante du passage d'un objet par référence
   PrintObject(foo1);
 
//--- déclare un pointeur sur un objet et le crée avec l'opérateur 'new'
   Foo *foo2=new Foo("foo2");
//--- variante de passage d'un pointeur vers un objet par référence
   PrintObject(foo2); // le pointeur vers l'objet est automatiquement converti par le compilateur
 
//--- déclare un tableau d'objets Foo
   Foo foo_objects[5];
//--- variante du passage d'un tableau d'objets
   PrintObjectsArray(foo_objects); // une fonction séparée pour passer un tableau d'objets
 
//--- déclare un tableau de pointeurs vers des objets de type Foo
   Foo *foo_pointers[5];
   for(int i=0;i<5;i++)
      foo_pointers[i]=new Foo("foo_pointer");
//--- variante du passage d'un tableau de pointeurs
   PrintPointersArray(foo_pointers); // une fonction séparée pour passer un tableau de pointeurs
 
//--- avant de terminer, assurez-vous de supprimer les objets créés en tant que pointeurs
   delete(foo2);
//--- supprime le tableau de pointeurs
   int size=ArraySize(foo_pointers);
   for(int i=0;i<5;i++)
      delete(foo_pointers[i]);
//---   
  }
//+------------------------------------------------------------------+
//|  Les objets sont toujours passés par référence                   |
//+------------------------------------------------------------------+
void PrintObject(Foo &object)
  {
   Print(__FUNCTION__,": ",object.m_id," Nom de l'objet=",object.m_name);
  }
//+------------------------------------------------------------------+
//| Passe un tableau d'objets                                        |
//+------------------------------------------------------------------+
void PrintObjectsArray(Foo &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
//+------------------------------------------------------------------+
//| Passe un tableau de pointeurs d'objets                           |
//+------------------------------------------------------------------+
void PrintPointersArray(Foo* &objects[])
  {
   int size=ArraySize(objects);
   for(int i=0;i<size;i++)
      PrintObject(objects[i]);
  }
//+------------------------------------------------------------------+

 

Vérifie le pointeur avant utilisation

Une tentative d'accès à un pointeur invalide provoque l'arrêt critique du programme. La fonction CheckPointer est utilisée pour vérifier un pointeur avant utilisation. Le pointeur peut être invalide dans les cas suivants :

  • le pointeur est égal à NULL ;
  • l'objet a été détruit à l'aide de l'opérateur delete.

Cette fonction peut être utilisée pour valider un pointeur. Une valeur différente de zéro indique que les données sont accessibles au niveau de ce pointeur.

class CMyObject
 {
protected:
  double             m_value;
public:
                     CMyObject(void);
                     CMyObject(double value) {m_value=value;};
                    ~CMyObject(void){};
  //---
  double             Value(void) {return(m_value);}
 };
//+------------------------------------------------------------------+
//| Fonction de démarrage du programme                               |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- crée un objet non initialisé
  CMyObject *pointer;
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("1. le pointeur est "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- initialise le pointeur
  pointer=new CMyObject(M_PI);
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("2. le pointeur est "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- supprime l'objet
  delete(pointer);
  if(CheckPointer(pointer)==POINTER_INVALID)
    Print("3. le pointeur est "EnumToString(CheckPointer(pointer)));
  else
    Print("3. pointer.Value()="pointer.Value());
 }
/*
   1le pointeur  est POINTER_INVALID
   2pointeur.Value()=3.141592653589793
   3le pointeur  est POINTER_INVALID
*/

Pour valider rapidement le pointeur, vous pouvez également utiliser l'opérateur "!" (LNOT) qui le vérifie via un appel implicite à la fonction CheckPointer. Cela permet d'écrire du code plus concis et plus clair. Vous trouverez ci-dessous les vérifications de l'exemple précédent :

//+------------------------------------------------------------------+
//| Fonction de démarrage du programme                               |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- crée un objet non initialisé
  CMyObject *pointer;
  if(!pointer)
    Print("1. le pointeur est "EnumToString(CheckPointer(pointer)));
  else
    Print("1. pointer.Value()="pointer.Value());
 
//--- initialise le pointeur
  pointer=new CMyObject(M_PI);
  if(!pointer)
    Print("2. le pointeur est "EnumToString(CheckPointer(pointer)));
  else
    Print("2. pointer.Value()="pointer.Value());
 
//--- supprime l'objet
  delete(pointer);
  if(!pointer)
    Print("3. le pointeur est "EnumToString(CheckPointer(pointer)));
  else
    Print("3. pointer.Value()="pointer.Value());
 }
/*
   1le pointeur  est POINTER_INVALID
   2pointeur.Value()=3.141592653589793
   3le pointeur  est POINTER_INVALID
*/

L'opérateur "==" est utilisé pour une vérification rapide de NULL. Par exemple : ptr==NULL ou ptr!=NULL.

Voir aussi

Variables, Initialisation des Variables, Portée de Visibilité et Cycle de Vie des Variables, Créer et Supprimer des Objets