Apply base class pointer to child class

 

Hello, 
I am struggling with some OOP coding in MQL5. 

1. Besides I am asking myself if I should used the standard library (the expert classes) because I am not seeing many people using them ? Are there recommendations (using DoEasy library or make my own ?) Thanks you for your replies

2. before gettings answers to this 1. , I want to solve some coding issues:


The question is, how can I call Child class methods from a parent perspective? I can't modify the parent class methods or make the attribute virtual as this parent class is part of the mql standard libraries. 

I am using the standard libraries (the classes in include/Expert). For my purpose, I extended those classes to add methods inside.  I get CExpertModel, and its children (see code below).

Let's consider this: using the expert standard library classes and I would like to, for example, to use the existing m_trailing variable instead of the workaround of creating the m_trail variable, because I also have to rewrite the parent methods that include the m_trailing variable.

May be I can use dynamic_cast or something else, but my skill are limited.

Any advice ? (i've read already post  https://www.mql5.com/en/forum/430039 )

here's my code (I simplified it to focus on the issue):


#include <Expert\ExpertBase.mqh>
#include <Expert\ExpertTrailing.mqh>

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CExpert_Tparams
  {
public:
   int               m_TrailingBehaviour;

   double                     m_TrailingActivate_1;
   double                     m_TrailingStop_1;
   double                     m_TrailingStep_1;


   void              CExpert_Tparams() {}
   void             ~CExpert_Tparams() {}

  };

//existing code
class CExpert : public CExpertBase
  {
protected:
   // [...] some other code
   CExpertTrailing   *m_trailing;                 // trailing stops object

   // [...] some other code
   virtual bool      InitTrailing(CExpertTrailing *trailing = NULL);
  };
//+------------------------------------------------------------------+
//| Initialization trailing object                                   |
//+------------------------------------------------------------------+
bool CExpert::InitTrailing(CExpertTrailing *trailing)
  {
   if(m_trailing != NULL)
      delete m_trailing;
//---
   if(trailing == NULL)
     {
      if((m_trailing = new CExpertTrailing) == NULL)
         return(false);
     }
   else
      m_trailing = trailing;
//--- initializing trailing object
   if(!m_trailing.Init(GetPointer(m_symbol), m_period, m_adjusted_point))
      return(false);
   m_trailing.EveryTick(m_every_tick);
   m_trailing.Magic(m_magic);
//--- ok
   return(true);
  }

// My code
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
class CExpertModelTrailing : public CExpertTrailing
  {
protected:

public:

   virtual bool               CheckTrailingStopLong(int positionIndex, double &sl, double &tp)  { return(false); }
   virtual bool               CheckTrailingStopShort(int positionIndex, double &sl, double &tp) { return(false); }

   // let's say for this example CExpert_Tparams class contains all the trailing parameters given by user input
   virtual bool              InitTrailingParameters(CExpert_Tparams &parameters)
     {
      return false;
     }
  };

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
class CExpertModel : public CExpert
  {
public:

   //this is the workaround I could find but it doesn't satisfy me nor answer the question
   CExpertModelTrailing    *m_trail;

   // [...] some other code

   //+------------------------------------------------------------------+
   //|                                                                  |
   //+------------------------------------------------------------------+
   bool              InitTrailing(CExpert_Tparams &parameters)
     {
      int trailingBehaviour = parameters.m_TrailingBehaviour;

      switch(trailingBehaviour)
        {
         case 0 :
            m_trail = new CTrailingNone();
            // I would like to be able to use m_trailing = new CTrailingNone();
            break;
         case 1 :
            m_trail = new CTrailingFixedPips();
            break;
         // [...] some other code
         default:
            m_trail = new CTrailingFixedPips();
            break;
        }

      if(!m_trail.Init(GetPointer(m_symbol), m_period, m_adjusted_point))
         return(false);   // launching at some point CExpertBase::Init(CSymbolInfo *symbol,ENUM_TIMEFRAMES period,double point)

      // this is where i would like some help:
      if(!InitTrailingParameters(parameters))
        {
         return false;
        }


      return true;
     }

   //+------------------------------------------------------------------+
   //|                                                                  |
   //+------------------------------------------------------------------+
   bool              InitTrailingParameters(CExpert_Tparams &parameters)
     {

      //this workaround is working
      if(!m_trail.InitTrailingParameters(parameters))
         return false;

      //this is NOT working as m_trailing is of type CExpertTrailing and doesn't have the child methods defined
      //if(!m_trailing.InitTrailingParameters(parameters))
      //   return false;
      return true;
     }
  };





//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
class CTrailingFixedPips : public CExpertModelTrailing
  {
protected:
   int               m_stop_level;
   int               m_profit_level;
public:

   //--- methods of initialization of protected data
   void              StopLevel(int stop_level)     { m_stop_level = stop_level;     }
   void              ProfitLevel(int profit_level) { m_profit_level = profit_level; }

   void              CTrailingFixedPips(void) : m_stop_level(30),
                     m_profit_level(50)
     {
     }
                    ~CTrailingFixedPips(void)
     {
     }

   bool              InitTrailingParameters(CExpert_Tparams &parameters)
     {

      StopLevel((int)parameters.m_TrailingStop_1);
      ProfitLevel((int)parameters.m_TrailingActivate_1);
      return true;
     }
  };
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
class CTrailingNone : public CExpertModelTrailing
  {
public:
   bool              InitTrailingParameters(CExpert_Tparams &parameters)
     {
      return true;
     }
  };
//+------------------------------------------------------------------+
Thank you :)


The Use of the MQL5 Standard Trade Class libraries in writing an Expert Advisor
The Use of the MQL5 Standard Trade Class libraries in writing an Expert Advisor
  • www.mql5.com
This article explains how to use the major functionalities of the MQL5 Standard Library Trade Classes in writing Expert Advisors which implements position closing and modifying, pending order placing and deletion and verifying of Margin before placing a trade. We have also demonstrated how Trade classes can be used to obtain order and deal details.
 

I could figure out another workaround that would be 

CExpertModelTrailing * m_trail = m_trailing;


but then I would have to add it in every child methods, right? is there another way ?


#include <Expert\ExpertBase.mqh>
#include <Expert\ExpertTrailing.mqh>

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CExpert_Tparams
  {
public:
   int                           m_TrailingBehaviour;

   double                     m_TrailingActivate_1;
   double                     m_TrailingStop_1;
   double                     m_TrailingStep_1;


   void              CExpert_Tparams() {}
   void             ~CExpert_Tparams() {}

  };

//existing code
class CExpert : public CExpertBase
  {
protected:
   // [...] some other code
   CExpertTrailing   *m_trailing;                 // trailing stops object

   // [...] some other code
   virtual bool      InitTrailing(CExpertTrailing *trailing = NULL);
  };
//+------------------------------------------------------------------+
//| Initialization trailing object                                   |
//+------------------------------------------------------------------+
bool CExpert::InitTrailing(CExpertTrailing *trailing)
  {
   if(m_trailing != NULL)
      delete m_trailing;
//---
   if(trailing == NULL)
     {
      if((m_trailing = new CExpertTrailing) == NULL)
         return(false);
     }
   else
      m_trailing = trailing;
//--- initializing trailing object
   if(!m_trailing.Init(GetPointer(m_symbol), m_period, m_adjusted_point))
      return(false);
   m_trailing.EveryTick(m_every_tick);
   m_trailing.Magic(m_magic);
//--- ok
   return(true);
  }

// My code
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
class CExpertModelTrailing : public CExpertTrailing
  {
protected:

public:

   virtual bool               CheckTrailingStopLong(int positionIndex, double &sl, double &tp)  { return(false); }
   virtual bool               CheckTrailingStopShort(int positionIndex, double &sl, double &tp) { return(false); }

   // let's say for this example CExpert_Tparams class contains all the trailing parameters given by user input
   virtual bool              InitTrailingParameters(CExpert_Tparams &parameters)
     {
      return false;
     }
  };

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
class CExpertModel : public CExpert
  {
public:




//this has been removed
 //  CExpertModelTrailing    *m_trail;
   // [...] some other code    //+------------------------------------------------------------------+    //|                                                                  |    //+------------------------------------------------------------------+    bool              InitTrailing(CExpert_Tparams &parameters)      {       int trailingBehaviour = parameters.m_TrailingBehaviour;       switch(trailingBehaviour)         {          case 0 :             m_trailing = new CTrailingNone();             // I would like to be able to use m_trailing = new CTrailingNone();             break;          case 1 :             m_trailing = new CTrailingFixedPips();             break;          // [...] some other code          default:             m_trailing = new CTrailingFixedPips();             break;         }       if(!m_trailing.Init(GetPointer(m_symbol), m_period, m_adjusted_point))          return(false);   // launching at some point CExpertBase::Init(CSymbolInfo *symbol,ENUM_TIMEFRAMES period,double point)       // this is where i would like some help:       if(!InitTrailingParameters(parameters))         {          return false;         }       return true;      }    //+------------------------------------------------------------------+    //|                                                                  |    //+------------------------------------------------------------------+    bool              InitTrailingParameters(CExpert_Tparams &parameters)      { //added CExpertModelTrailing * m_trail = m_trailing;       //this workaround is working       if(!m_trail.InitTrailingParameters(parameters))          return false;       //this is NOT working as m_trailing is of type CExpertTrailing and doesn't have the child methods defined       //if(!m_trailing.InitTrailingParameters(parameters))       //   return false;       return true;      }   };
 

Anyone has an idea ? 

maybe I'm over complicating it and I just have to use 

CExpertModelTrailing * m_trail = m_trailing;


?

 

You removed the pointer variable from the class. So how do you expect to assign to a nonexistent variable.

You don't “just have to use” m_trail. Use the variable m_trailing defined in your base class. You are causing your own problem.

 

Thank you for your reply. I don't understand quite well when you say "You removed the pointer variable from the class." Would you mind explaining ?

I think maybe I explained wrongly:

The Standard Library's CExpert has a m_trailing variable

CExpertTrailing   *m_trailing;                 // trailing stops object

which is the type of  CExpertTrailing.

So it doesn't have the added child methods the user (me) can create in its child  (CExpertModelTrailing : public CExpertTrailing)

I could just instantiate the child class to get access to all the methods. But the standard library's automation is instantiating the  CExpertTrailing class (with m_trailing varialble)...And we can't modify it because it will be overridden on the next metatrader5 update.

If the child class has a B() method I can't access if by using 

double b = m_trailing.B();

but I can if I do 

CExpertModelTrailing * m_trail = m_trailing;
double b = m_trail.B();

Just thought it wasn't very elegant to do so. Or my coding skills are limited and that's why I am asking for advice.

any thoughts on that ?

 

well I guess if no one is replying, means that redefining a variable is the only way to access a child method, when accessing the parent objet with

CExpertModelTrailing * m_trail = m_trailing;
double b = m_trail.B();
 
DidMa #:

well I guess if no one is replying, means that redefining a variable is the only way to access a child method, when accessing the parent objet with

You could do a cast of the pointer.


double b = ((CExpertModelTrailing *)m_trailing).B();
 
DidMa #:

well I guess if no one is replying, means that redefining a variable is the only way to access a child method, when accessing the parent objet with

The true question is why do you need to access this child method ?

I would even say why do you need to use inheritance at all ?

 
DidMa:

I'm not sure I understand your question correctly.

I sometimes have a situation where child classes are initialized differently. I did something like this:

class CParent
  {
public:
   void someMethod() {}
  };

class CChild1 : public CParent
  {
private:
   int member;
public:
   void initialize(int a_1) { member = a_1; };
  };

class CChild2 : public CParent
  {
private:
   double member1;
   double member2;
public:
   void initialize(double a_1, double a_2) { member1 = a_1; member1 = a_2;};
  };

CParent* objects[2];

int OnInit()
  {
   // Assign a descriptor of created object to the temporary pointer of the child class
   CChild1* tempPtrChild1 = new CChild1;
   CChild2* tempPtrChild2 = new CChild2;
   // Using temporary pointers, call methods of the child class
   tempPtrChild1.initialize(1);
   tempPtrChild2.initialize(1.0, 2.0);
   // This can be done without using dynamic_cast
   objects[0] = tempPtrChild1;
   objects[1] = tempPtrChild2;
   // -------
   return(CheckPointer(objects[0]) == POINTER_DYNAMIC && CheckPointer(objects[1]) == POINTER_DYNAMIC ? INIT_SUCCEEDED : INIT_FAILED);
  }

void OnTick()
  {
   objects[0].someMethod();
   objects[1].someMethod();
  }

Code just to demonstrate the idea. Of course, I did not run it and did not test it.

 
Alain Verleyen #:

The true question is why do you need to access this child method ?

I would even say why do you need to use inheritance at all ?

Thank you Alain for your reply.

I guess this post is more about good practices than something else.
I created a simple model where my classes inherit the standard library classes. So I can add my own methods without the stress of losing my work where MT5 is updating. Maybe I should not use Inheritance and I'm open to other practice with a simple example if possible. I would be happy to implement it according to my coding skills.

I want to access it because natively what the child method B() is doing is not implemented (that's what usually specialisation classes are doing). 

The purpose is also to standardise these specialisations calls (idea of kind of strategy design pattern): 

for example through an input parameter, the user can choose the type of trailing he wants, as the standard library is instanciating trailing like this:

//+------------------------------------------------------------------+
//| Initialization trailing object                                   |
//+------------------------------------------------------------------+
bool CExpert::InitTrailing(CExpertTrailing *trailing)
  {
   if(m_trailing!=NULL)
      delete m_trailing;
//---
   if(trailing==NULL)
     {
      if((m_trailing=new CExpertTrailing)==NULL)
         return(false);
     }
   else
      m_trailing=trailing;
//--- initializing trailing object
   if(!m_trailing.Init(GetPointer(m_symbol),m_period,m_adjusted_point))
      return(false);
   m_trailing.EveryTick(m_every_tick);
   m_trailing.Magic(m_magic);
//--- ok
   return(true);
  }

I can do something like this: 

// CExpert_Tparams is the class where the specific trailing parameters are stored

//this code is located in the inherited class of CExpert : CExpertModel.
bool              InitTrailing(CExpert_Tparams &parameters)
     {
// [...] some code...
      ENUM_TRAILING_STRATEGY trailingBehaviour = (ENUM_TRAILING_STRATEGY)parameters.m_TrailingBehaviour;

      switch(trailingBehaviour)
        {
         case TRAILING_STRATEGY_NONE :
            m_trailing = new CTrailingNone();        
            break;
         case TRAILING_STRATEGY_CLASSIC :
               m_trailing = new CTrailingFixedPips();
            break;
// [...] some code...

// this is an attribute of this CExpertModel Class: CExpertModelTrailing    *m_trail;
m_trail = m_trailing;

But by doing

m_trail = new CTrailingNone(); 

so, the already present attribute (and used everywhere in the standard library) m_trailing is not used. 

That's why I chose (maybe a mistake) to use 

m_trailing = new CTrailingNone(); 
m_trail = m_trailing;
//[...] do some actions 

This could be implemented for any type of complete "strategy" calling signals, money management and whatever else that could need a specific class instanciation on the fly, depending on, for example, input parameters.

Open to any suggestion. I guess this is just a lack of mql/C++ coding knowledge...

 
A guess I wouldn't bother much if I wouldn't be using the standard library that I can't modify, and just make the parent class as I want, create my own "standard library", call the virtual methods etc. 
Reason: