Download MetaTrader 5

OOP, next problem: how many instances do I have and why is one pointer still NULL??

To add comments, please log in or register
Carl Schreiber
7228
Carl Schreiber  

Hi,

hope you don't mind me being nasty. Anyway this is my script and I get at this runtime error:

2016.09.21 15:26:50.468 testClass02 EURUSD,M1: invalid pointer access in 'testClass02.mq4' (91,12)

For your understanding. I have two base classes CI and CQ and one derived class TestDerv1CI (ancestor of CI).

In the script I define an array of ref. to CQ which is one of the parameter of the constructor of CI (used even by TestDerv1CI):

void OnStart() {
   CQ* rCQ[];                                   // ref. to CQ
   TestDerv1CI* t1 = new TestDerv1CI(rCQ, 1);   // constructor of ancestor of CI using its constr.-method
   int i1 = t1.setPara( 11, 12 );               // <== in this method I get the error :(
}

The constructor of TestDerv1CI (ancestor of CI):

CI::CI(CQ* &q[], const int id){ // constructor CI
  m_instanc = TimeLocal();
  int n = ArraySize(q);  // start to create another (new) instance of CQ and save it in the array
  ArrayResize(q,n+1);    // one more
  q[n] = new CQ(id);     // create new instance
  m_rCQ = q[n];          // store the ref. to CQ-class in the class method  line 52 
  m_id = id;             // here I place the toggle breakpoint of the debugger  
}

Expecting that the reference to CQ was stored I just request the ID of CQ in the method setParas of the derived class (line 86ff):

ENUM_INIT_RETCODE TestDerv1CI::setPara( const int p1, const int p2 ) {
   m_p1=p1;  m_p2=p2;
   m_qid = m_rCQ.getID(); // <= Error because pointer m_rCQ still NULL ?? WHY???
   m_sid = "id: "+(string)+m_id+", "+(string)m_p1+", "+(string)m_p2+" "+TimeToString(m_instanc,TIME_MINUTES|TIME_SECONDS);
   return(INIT_SUCCEEDED);
}

I am thinking that I have created a new instance of CQ in the constructor of TestDerv1CI  and stored the reference of it in

CQ* m_rCQ;
...
q[n] = new CQ(id);     // and now??
m_rCQ = q[n];          // store the in the ref to its CQ-class

but the next call of a method of TestDerv1CI  (setParas(..)) this pointer is still NULL?

So where is my instance CQ? If I access it through the references stored in the array of the script (CQ* rCQ[]) I don't have any problem???

Well I am interested in an explanation - the solution would be just to ad the array to the parameter, but why am I in trouble and have to store the reference twice? Where is the first stored reference?

If the reference first stored is not placed in TestDerv1CI variable m_rCQ - does this mean that now exists one instance of CI and one of TestDerv1C??

Thanks!

Carl

Files:
Blahtech Limited
5123
James Cater  

You keep redefining instance variables in the derived classes that are already in the base class. Inheritance means you inherit the data members as well as the functions.

Make the base class data variables protected and remove the duplicates and your code should work. (As I did in your previous example)

Carl Schreiber
7228
Carl Schreiber  
James Cater:

You keep redefining instance variables in the derived classes that are already in the base class. Inheritance means you inherit the data members as well as the functions.

Make the base class data variables protected and remove the duplicates and your code should work. (As I did in your previous example)

But when I make m_rCQ the pointer to CQ protected in the base class then every derivative of CQ will have a pointer to the same CQ-instance. That is not what I want! Some might share the same but some need a different CQ-instance.

Beside that I created an instance of TestDerv1CI - I think, because I use its constructor - so why has it 'forgotten' the pointer?

Blahtech Limited
5123
James Cater  
Carl Schreiber:

But when I make m_rCQ the pointer to CQ protected in the base class then every derivative of CQ will have a pointer to the same CQ-instance. That is not what I want! Some might share the same but some need a different CQ-instance.

Beside that I created an instance of TestDerv1CI - I think, because I use its constructor - so why has it 'forgotten' the pointer?

Data is data, once you derive from a class you will always have the pointer in the base class. You can't get away from this.

If you don't want some of the derived cases to have the data then you should not define it in the base class and let the derived classes define the data themselves.


In response to your question. You have not set the m_rCQ in the derived class anywhere, so no wonder it is NULL.

Carl Schreiber
7228
Carl Schreiber  

OK, lets solve the problem and introduce another derived class and I get really strange things:

I defined a temp-pointer with which I get a valid pointer to CQ in the derived class.


That's from the debugger.

Now m_id in t1 and t2 is NOT set ?? But correctly displayed in s1 and s2. Same with m_instance, the time it has been instantiated.

This is hard to understand. Where are the m_id 1 and 2 stored. Does this mean I have now 4 objects two CI and two TestDerv1CI and TestDerv2CI.

This let me seriously doubt about the concept of of inheritance. What I see here seems to be not an inheritance but just doubling the data and sometimes it is taken from here sometimes from there. :(

Please let me know where I am wrong!

Calli

Files:
Stanislav Korotky
21039
Stanislav Korotky  

As a reply for your personal request to visit this topic,

I must say that I'm still confident that if you want someone to help you solve the problems your should point out what you want to achieve (from applicational point of view, not as you decided to implement it). It looks like your class composition should be replaced with something else. I don't get your code at the moment.

Carl Schreiber
7228
Carl Schreiber  

One problem is solved. My misunderstanding was about the relationship of the base class and its derived class.

So in the class CI I had to make all the variables "protected" and (this was my misunderstanding) they are not shared among other derivatives!!:

class CI {
   protected:
      int m_id;
      datetime m_instanc;
      CQ* m_rCQ;   
      CI(CQ* &q[], const int id); // contructor
...

and in its derivative the new and specific vars. can be "private" while the vars already defined in CI must not be declared again:

class TestDerv1CI : public CI  {
private:
         int m_p1, m_p2;
         string m_sid, m_qid;
...

So now it works:


Two classes and they show the same values as if the variables were request their values.

But there is something else that I find some what cumbersome in OnStart() (line136,137 and 139,140):

   ...
   TestDerv1CI* t1 = new TestDerv1CI(rCQ, 1 );
   int i1 = t1.setPara( 11, 12 );
   ...

I think it should be possible to have only one method that create the instance and sets it parameters instead of one constructor and an extra setting method - something like the method advancedSetting(..):

class TestDerv1CI : public CI  {
...
public:
                        TestDerv1CI(CQ* &q[], const int id) : CI(q, id) {}; // contructor  
                       ~TestDerv1CI() {};
   TestDerv1CI*         advancedSetting( CQ* &q[], const int id, const int p1, const int p2, ENUM_INIT_RETCODE &_init );
}
...
TestDerv1CI* TestDerv1CI::advancedSetting( CQ* &q[], const int id, const int p1, const int p2, ENUM_INIT_RETCODE &_init ) {
   TestDerv1CI* retRev = new TestDerv1CI(q,id);
   m_p1=p1;  
   m_p2=p2; 
   m_qid = m_rCQ.getID(); // line 91 <= Error because pointer still NULL ???
   m_sid = "id: "+(string)+m_id+", "+(string)m_p1+", "+(string)m_p2+" "+TimeToString(m_instanc,TIME_SECONDS);
   _init = INIT_SUCCEEDED;
   return(retRev);
}

Compiling (only) this causes no problem! But as soon as I want to use it -  the compiler grumbles:

TestDerv1CI* t0 = TestDerv1CI::advancedSetting( rCQ,0, 2,3, _init ); // <= 'advancedSetting' - access to non-static member or function  testClass04.mq4 137     35

To be able to run the script I commented this line, if you de-comment it, you'll get the a.m. compiler error.

Well the idea is simply to have only one method that creates a new instance by using the constructor of the base class CI and set its parameter hereafter!

And I do want to use the constructor of the base class! I do want to use the benefits of OOP and the inheritance. Otherwise if I have to write for every derivative class individual constructors why do O need/have OOP with inheritance?

As I can't see any logical reason, why this shouldn't work - I ask here what to do.

How can I call this method advancedSetting(..) without already having an instance this function belongs to?

Files:
Stanislav Korotky
21039
Stanislav Korotky  
Carl Schreiber:

So in the class CI I had to make all the variables "protected" and (this was my misunderstanding) they are not shared among other derivatives!!:

You're wrong. Protected members are accessible in descendants. They are "shared" (inherited).

Carl Schreiber:

and in its derivative the new and specific vars. can be "private" while the vars already defined in CI must not be declared again:

No. You can redefine them again and change access rights for example by making private while they were initially protected (private ones will become inaccessible in further descendants).

Carl Schreiber:

To be able to run the script I commented this line, if you de-comment it, you'll get the a.m. compiler error.

Well the idea is simply to have only one method that creates a new instance by using the constructor of the base class CI and set its parameter hereafter!

And I do want to use the constructor of the base class! I do want to use the benefits of OOP and the inheritance. Otherwise if I have to write for every derivative class individual constructors why do O need/have OOP with inheritance?

It looks like you're trying to invent a well-known "factory method" design pattern. In order to get your code work you need to declare the method static. Anyway I recommend you to read about OOP design patterns - they provide ready-made solutions for all imaginable tasks you have (and trying to solve on your own).
Factory method pattern - Wikipedia, the free encyclopedia
Factory method pattern - Wikipedia, the free encyclopedia
  • en.wikipedia.org
In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child...
Carl Schreiber
7228
Carl Schreiber  
Stanislav Korotky:

You're wrong. Protected members are accessible in descendants. They are "shared" (inherited).

No. You can redefine them again and change access rights for example by making private while they were initially protected (private ones will become inaccessible in further descendants).

It looks like you're trying to invent a well-known "factory method" design pattern. In order to get your code work you need to declare the method static. Anyway I recommend you to read about OOP design patterns - they provide ready-made solutions for all imaginable tasks you have (and trying to solve on your own).

Thank you for your effort. Even though I still don't really understand which value of the instances of the descendant classes will be where and when after that what you said. :(

"You're wrong. Protected members are accessible in descendants. They are "shared" (inherited)."

Is the structure shared like same variables with the same type and same names but they can have different values - or do they interfere?

  1. Imagine a graphical object as a base class it has 1 graphical point - the anchor, (its a kind of id and/or the point at which it pointed from on the chart), <= this should never been created its more a collection of common variables and methods for its descendants,
  2. a triangle should be a descendant, which has its individual anchor and two more point,
  3. another triangle has a different anchor and two different point
  4. a square has its anchor and three different points

Now I want to have a constructor of the base class, which places the anchor on the chart and does all this common stuff. It is called by all descendants at creation time but should only help to create the descendants! That means if I want to create a triangle with a given anchor this anchor (id) should exist only once (if not provided a second time)! The next triangle that I want to create with a different anchor must not interfere the previous one - even though both use the same constructor of their common base class but with a different value for the anchor.

This seemed to be achieved by my script as the two descendants of CI do have different IDs and timestamps. Can you provide code examples of my code that the two descendants do interfere each other - as you said "they are shared"? E.g. can one of the triangles can get/set that values of one of the other triangles if it does not have a pointer to it?

--------------------------

You said the same as the compiler I need/tried to access a static something: " ... you need to declare the method static."

But how do I do it in mql4? The reference seem to support only static variables?

And what would it mean if a method is declared as static? But static means: "These data members are shared by all instances of this class and are stored in one place".

This is not what I want!

In OOP with the concept of inheritance this is somewhat different - at least to me :(

Your point of the factory method doesn't really help me, as I want to know whether I can do what I described in MQL4 and if so, how can I do it.

I try to learn OOP by an example of what I really want to realize. The problem is that there is still a difference between different languages that do OOP (C++, Java,...). And as I learned not everything that is explained as OOP is implemented in MQL4.

I hope you don't mind, but these are the main problems for my mind to start thinking in OOP as I still think in terms of global and local variables and functions to change them. There I do exactly know where and how can I get/set the value of each variable at any time!

Anyway thanks for your effort!!

Stanislav Korotky
21039
Stanislav Korotky  
Carl Schreiber:

"You're wrong. Protected members are accessible in descendants. They are "shared" (inherited)."

...

This seemed to be achieved by my script as the two descendants of CI do have different IDs and timestamps. Can you provide code examples of my code that the two descendants do interfere each other - as you said "they are shared"? E.g. can one of the triangles can get/set that values of one of the other triangles if it does not have a pointer to it?

You seems mixing notions of a class and an object. In your initial post (for which I wrote my previous answer) you asked about "sharing" between base and derived classes. At least it looks so from the context: "in the class CI I had to make all the variables "protected" and they are not shared among other derivatives".

When you create an object, it of course contains all data defined in its class and ancestor classes. Objects do not share values of their variables, unless a variable is defined as static - such variable exists in only one "exemplar" for all objects of the class. Statis methods behaves the same. A static method is accessed through a name of its class and does not require an object for execution. It's a kind of single "exemplar", and it can not deal with object (non-static) variables.

Declare static method the same as you do for a variable.

Both C++ and Java are very well suited for learning OOP. They are similar to MQL.

Design patterns are mostly not language specific. You asked about a method (other than constructor) to create an instance of an object in MQL. This is the "factory method" design pattern. You should learn it. Then it will help you.

To add comments, please log in or register