Can't get access to internal object member

 

Hi there,

I have a class CHiLoTracker that is instantiated in a method called from an EA's OnInit.

Below is a class that I found on this forum.

#define SORT_ASCENDING  1
#define SORT_DESCENDING 2

#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
template<typename T>
class CObjVector : public CArrayObj
  {
private:

public:
                     CObjVector() {}
                     CObjVector(const CObjVector &hilo) {}
                     
   CObjVector *operator=(const CObjVector &hilo)
     {
      return(GetPointer(this));
     }
     
   T  *operator[](const int index) const { return(T*)At(index);}
  };

The following class snippet is the main class that does the work, called from my EA's OnInit. You can see it has a private field that is called _confirmed. From calling a method (ScanLevels) on this class, the _confirmed object has instanced of CHiLo added to it. I have a getter that returns a reference to _confirmed.

class CHiLoTracker
  {

private:
   CObjVector<CHiLo> _confirmed;

...

public:
                     CHiLoTracker();
                    ~CHiLoTracker();
   void              ScanLevels(int barsBack);
   CObjVector<CHiLo>GetConfirmed();

  };

CObjVector<CHiLo>CHiLoTracker::GetConfirmed()
  {

   return _confirmed;

  }

Below is the definition of CHiLo.

class CHiLo : public CObject
  {
private:

   bool              _isVbtpHigh;
   datetime          _pivotHiLoTime;
   double            _pivotHiLoLevel;
   datetime          _confirmedTime;
   double            _confirmedLevel;

public:
                     CHiLo();
                     CHiLo(
                                             bool isVbtpHigh,
                                             datetime pivotHiLoTime,
                                             double pivotHiLoLevel,
                                             datetime confirmedTime,
                                             double confirmedLevel);

                     CHiLo(const CHiLo &hilo);

                    ~CHiLo();
   virtual int       Compare(const CObject *node,const int mode=0) const override;
   string            GetPivotLevel();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHiLo::CHiLo()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHiLo::~CHiLo()
  {
  }
//+------------------------------------------------------------------+
CHiLo::CHiLo(
             bool isVbtpHigh,
             datetime pivotHiLoTime,
             double pivotHiLoLevel,
             datetime confirmedTime,
             double confirmedLevel)
  {

   _isVbtpHigh=isVbtpHigh;
   _pivotHiLoTime=pivotHiLoTime;
   _pivotHiLoLevel=pivotHiLoLevel;
   _confirmedTime=confirmedTime;
   _confirmedLevel=confirmedLevel;

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHiLo::CHiLo(const CHiLo &hilo)
  {

   _isVbtpHigh=hilo._isVbtpHigh;
   _pivotHiLoTime=hilo._pivotHiLoTime;
   _pivotHiLoLevel=hilo._pivotHiLoLevel;
   _confirmedTime=hilo._confirmedTime;
   _confirmedLevel=hilo._confirmedLevel;

  }
//+------------------------------------------------------------------+
int CHiLo::Compare(const CObject *node,const int mode=0)const
  {
/*
   MyClass *that = (MyClass*)node;
   int comp = StringCompare(this.Symbolname,that.Symbolname);
   if(mode == SORT_DESCENDING)
      return -comp;
   else
      return comp;
*/
   return 1;

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string CHiLo::GetPivotLevel()
  {

   return TimeToStr(_pivotHiLoTime);


  }

Below is a fragment of calling ScanLevels after which, I want to do things with the items in the _confirmed collection.

int Main()
  {

   Tracker.ScanLevels(BarsBack);
   
   CObjVector<CHiLo> items = Tracker.GetConfirmed();
   
   Alert(items.Total());
   

   return(0);

  }

When I put a Print inside the GetConfirmed method, it tells me there are 16 items in the collection. However, when I Alert the items.Total(), it returns 0 (Zero). 

I've tried all kinds of things and Googled around but nothing I do seems to bring me back a reference to _confirmed.

I am new to MQ4 and haven't used CPP before (I have used C#). So, the whole "pointer" issue is alien to me.

If anyone can kindly take a look at my code and perhaps suggest where I am going wrong, I would greatly appreciate it! :)

Many thanks.

 
Geester:

Hi there,

I have a class CHiLoTracker that is instantiated in a method called from an EA's OnInit.

Below is a class that I found on this forum.

The following class snippet is the main class that does the work, called from my EA's OnInit. You can see it has a private field that is called _confirmed. From calling a method (ScanLevels) on this class, the _confirmed object has instanced of CHiLo added to it. I have a getter that returns a reference to _confirmed.

Below is the definition of CHiLo.

Below is a fragment of calling ScanLevels after which, I want to do things with the items in the _confirmed collection.

When I put a Print inside the GetConfirmed method, it tells me there are 16 items in the collection. However, when I Alert the items.Total(), it returns 0 (Zero). 

I've tried all kinds of things and Googled around but nothing I do seems to bring me back a reference to _confirmed.

I am new to MQ4 and haven't used CPP before (I have used C#). So, the whole "pointer" issue is alien to me.

If anyone can kindly take a look at my code and perhaps suggest where I am going wrong, I would greatly appreciate it! :)

Many thanks.


It looks like there could be a lot going wrong with this and you haven't provided enough code to determine what you are attempting to accomplish.  ... but straight away, this method doesn't do anything except return the pointer to the object you are working with. And also the whole point of the templated object vector is to remain unspecified. 

     CObjVector *operator=(const CObjVector &hilo)
     {
      return(GetPointer(this));
     }

Also, your Compare methods must return the default of 0 not 1 or -1.


Finally, here is an example of a design pattern that I would use to do what I think you are trying to do. 

#include <Arrays\ArrayObj.mqh>
template<typename T>
class CObjVector : public CArrayObj
{
public: T* operator[](const int index) const { return At(index);}
};
//+------------------------------------------------------------------+
class CHiLo : public CObject
{
public:
   static int  m_instances;
   int         m_my_instance;
   CHiLo(){ m_my_instance= ++m_instances;}
   void PrintInstanceNumber(){ ::Print("I am instance number ",m_my_instance);}
};
int CHiLo::m_instances = 0;
//+------------------------------------------------------------------+
class CHiLoTracker : public CObjVector<CHiLo>
{
public:
   void  PsuedoMethod()
   {
      for(int i=0;i<10;i++)
         this.Add(new CHiLo);
   }
};
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   CHiLoTracker tracker;
   tracker.PsuedoMethod();
   for(int i=0;i<tracker.Total();i++)
      tracker[i].PrintInstanceNumber();
}
//+----------------------------------------
 
nicholishen:

It looks like there could be a lot going wrong with this and you haven't provided enough code to determine what you are attempting to accomplish.  ... but straight away, this method doesn't do anything except return the pointer to the object you are working with. And also the whole point of the templated object vector is to remain unspecified. 

Also, your Compare methods must return the default of 0 not 1 or -1.


Finally, here is an example of a design pattern that I would use to do what I think you are trying to do. 


Hi @nicholishen - many thanks for the heads-up and your very helpful comments and observations! :)

Your suggestion to make my HiLoTracker inherit from CObjVector was totally correct and I don't know why I didn't think of that myself - dohh! As soon as I did that, I didn't need to hold a private instance of:

CObjVector<CHiLo>_confirmed;

And then, the problem of how to access it from outside of HiLoTracker disappeared.

I totally take your point about having a concrete class reference inside of a generic templated class. I only added that code during my desperate attempts to get the whole thing working.

As to my Compare method, I hadn't actually implemented anything there and it was actually commented out. I just returned a value of 1 for the sake of compilation. My whole reason for wanting to create an object of type CObjVector<CHiLo> was to store instances of CHiLo that I could later sort by a datetime member of CHiLo. Before I did that, I needed to know that I could at least access my collection of CHiLo instances from outside of HiLoTracker. Now, thanks to your help, I have achieved that!

I really appreciate your time and trouble helping me out with this. It seems so obvious now but before your help, I was getting nowhere, fast!

As it goes, I'd still like to know how I could have accessed the original _confirmed reference using a getter? As I mentioned in my original post, I just kept getting an object with no CHiLo values inside the CObjVector collection. For the sake of understanding, I'd like to figure this out.


Regards!

--Geester

 
Geester:

Hi @nicholishen - many thanks for the heads-up and your very helpful comments and observations! :)

Your suggestion to make my HiLoTracker inherit from CObjVector was totally correct and I don't know why I didn't think of that myself - dohh! As soon as I did that, I didn't need to hold a private instance of:

And then, the problem of how to access it from outside of HiLoTracker disappeared.

I totally take your point about having a concrete class reference inside of a generic templated class. I only added that code during my desperate attempts to get the whole thing working.

As to my Compare method, I hadn't actually implemented anything there and it was actually commented out. I just returned a value of 1 for the sake of compilation. My whole reason for wanting to create an object of type CObjVector<CHiLo> was to store instances of CHiLo that I could later sort by a datetime member of CHiLo. Before I did that, I needed to know that I could at least access my collection of CHiLo instances from outside of HiLoTracker. Now, thanks to your help, I have achieved that!

I really appreciate your time and trouble helping me out with this. It seems so obvious now but before your help, I was getting nowhere, fast!

As it goes, I'd still like to know how I could have accessed the original _confirmed reference using a getter? As I mentioned in my original post, I just kept getting an object with no CHiLo values inside the CObjVector collection. For the sake of understanding, I'd like to figure this out.


Regards!

--Geester

No worries, glad I could help. 


You can use a getter to return the pointer to the object itself 

#include <Arrays\ArrayObj.mqh>
template<typename T>
class CObjVector : public CArrayObj
{
public: T* operator[](const int index) const { return At(index);}
};
//+------------------------------------------------------------------+
class CHiLo : public CObject
{
protected:
   static int  m_instances;
   int         m_my_instance;
public:
   CHiLo(){ m_my_instance= ++m_instances;}
   void PrintInstanceNumber(){ ::Print("I am instance number ",m_my_instance);}
};
int CHiLo::m_instances = 0;
//+------------------------------------------------------------------+
class CHiLoTracker 
{
private:
   CObjVector<CHiLo> m_list;
public:
   void  PsuedoMethod()
   {
      for(int i=0;i<10;i++)
         m_list.Add(new CHiLo);
   }
   CObjVector<CHiLo>* GetListPointer() { return &m_list; }
};
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   CHiLoTracker tracker;
   tracker.PsuedoMethod();
   CObjVector<CHiLo> *list = tracker.GetListPointer();
   for(int i=0;i<list.Total();i++)
      list[i].PrintInstanceNumber();
}
//+------------------------------------------------------------------+


Or you can create a method to copy the contents from one vector to another

#include <Arrays\ArrayObj.mqh>
template<typename T>
class CObjVector : public CArrayObj
{
public: T* operator[](const int index) const { return At(index);}
};
//+------------------------------------------------------------------+
class CHiLo : public CObject
{
protected:
   static int  m_instances;
   int         m_my_instance;
public:
   CHiLo(){ m_my_instance= ++m_instances;}
   void PrintInstanceNumber(){ ::Print("I am instance number ",m_my_instance);}
};
int CHiLo::m_instances = 0;
//+------------------------------------------------------------------+
class CHiLoTracker 
{
private:
   CObjVector<CHiLo> m_list;
public:
   void  PsuedoMethod()
   {
      for(int i=0;i<10;i++)
         m_list.Add(new CHiLo);
   }
   void CopyCollection(CObjVector<CHiLo> &list)
   {
      list.AddArray(&m_list);
   }
};
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   CHiLoTracker tracker;
   tracker.PsuedoMethod();
   CObjVector<CHiLo> list;
   tracker.CopyCollection(list);
   for(int i=0;i<list.Total();i++)
      list[i].PrintInstanceNumber();
}
//+------------------------------------------------------------------+
 
nicholishen:

No worries, glad I could help. 


You can use a getter to return the pointer to the object itself 


Or you can create a method to copy the contents from one vector to another


Hey @nicholishen, that's awesome additional information. Thank you so much! :)

Cheers,

--G



Reason: