[Help with OOP] How to correctly resolve a static member?

 

I need a static member with an automatic pointer. How to resolve it correctly?

Here's how I did:

class CCommonThings
  {
public:
   void method()        { Print("CCommonThings::method() called"); }
        CCommonThings() { Print("CCommonThings constructor");      }
  };

class CSomeClass
  {
private:
   static CCommonThings common;
public:
                        CSomeClass() { common.method(); }
  };

CCommonThings CSomeClass::common;

void OnStart() 
  { 
   CSomeClass arrayTempName[3];
  }

And it works - only 1 CCommonThings instance is created:

But is this code correct? Judging by the fact that everything works - yes. But I want someone to confirm this. I have not seen a static member resolve without an assignment statement. I came up with this myself and didn't expect it to work😄

 
Vladislav Boyko:

I need a static member with an automatic pointer. How to resolve it correctly?

private:
   static CCommonThings *common;
CCommonThings *CSomeClass::common=new CCommonThings();

Automatic object pointer needs to be deleted explicitly, and so it is left undeleted in the log after running this.

For deletion, you can add a destructor:

                    ~CSomeClass() {if(common) delete common;}
 
Amir Yacoby #: For deletion, you can add a destructor:

That will not work. The variable is static, not a regular member. There can be any number of objects, but only one static.

Amir Yacoby #:

CCommonThings *CSomeClass::common=new CCommonThings();

Do not new at the global scope, since you can not delete at global scope. New in OnInit, delete in OnDeinit.

 
Amir Yacoby #:

Automatic object pointer needs to be deleted explicitly, and so it is left undeleted in the log after running this.

For deletion, you can add a destructor:

Wrong. That's not an automatic pointer you are using, but a dynamic pointer.

In the OP code "&CSomeClass::common" is an automatic pointer.

 
Alain Verleyen #:

Wrong. That's not an automatic pointer you are using, but a dynamic pointer.

In the OP code "&CSomeClass::common" is an automatic pointer.

I can agree but something is not so clear for me here in that terminology.

  CCommonThings a;
  Print(CheckPointer(a)); 		// This does not compile, you should: 
  Print(CheckPointer(GetPointer(a)));   // which returns 2-Automatic pointer

So, when you get the pointer using GetPointer() you recieve it as auto-poineter. Before doing that, you say it's still a pointer?

*-Ok, read again the GetPointer() and it's clear, it has a pointer, you should just get it. 

**-So, yes, OP you are doing it right if you need the auto-pointer and not the dynamic.
Documentation on MQL5: Common Functions / GetPointer
Documentation on MQL5: Common Functions / GetPointer
  • www.mql5.com
GetPointer - Common Functions - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 

Thanks everyone for the replies! :)


Vladislav Boyko:

But is this code correct?

I conclude that this code is correct based on:

  1. It compiles and works.
  2. Nobody said the code is wrong.

In fact, there were several static methods and members that wrapped nicely in a separate class (were related in meaning). This made the code less cumbersome and more readable.

But I wanted to indicate that this class is a component of another class and should not be used as a self-sufficient.

I could declare this class in global scope and store a static pointer to it. But that would make the code cumbersome (because the pointer has to be received and passed during initialization). And it would break encapsulation.

I could use inheritance. But that would create confusion. Especially if we imagine that there can be several such subclasses. Inheritance is clearly not appropriate here.


So far, for me, this method is the most convenient for wrapping class components without breaking encapsulation.

 
Amir Yacoby #:

I can agree but something is not so clear for me here in that terminology.

So, when you get the pointer using GetPointer() you recieve it as auto-poineter. Before doing that, you say it's still a pointer?

*-Ok, read again the GetPointer() and it's clear, it has a pointer, you should just get it. 

**-So, yes, OP you are doing it right if you need the auto-pointer and not the dynamic.
Print(CheckPointer(a)); 		// This does not compile, you should: 
Because a is not a pointer by itself. You can use GetPointer(a) or &a.
 
William Roeder #:

That will not work. The variable is static, not a regular member. There can be any number of objects, but only one static.

Do not new at the global scope, since you can not delete at global scope. New in OnInit, delete in OnDeinit.

Not correct, common is not in global scope. It's in the class scope, only it is static. When you need it to have dynamic poperties, you should use new and delete.

CCommonThings *CSomeClass::common=new CCommonThings();

CSomeClass::   -> That's a scope declaration, the class scope.

 
Alain Verleyen #:
Because a is not a pointer by itself. You can use GetPointer(a) or &a.

Right, I edited my answer while you were probably typing. Thank you.

 
Vladislav Boyko #:

Thanks everyone for the replies! :)


I conclude that this code is correct based on:

  1. It compiles and works.
  2. Nobody said the code is wrong.
Not sure why you think it could be wrong, it has nothing special ? The constructor is the initialization.

    In fact, there were several static methods and members that wrapped nicely in a separate class (were related in meaning). This made the code less cumbersome and more readable.

    But I wanted to indicate that this class is a component of another class and should not be used as a self-sufficient.

    I could declare this class in global scope and store a static pointer to it. But that would make the code cumbersome (because the pointer has to be received and passed during initialization). And it would break encapsulation.

    I could use inheritance. But that would create confusion. Especially if we imagine that there can be several such subclasses. Inheritance is clearly not appropriate here.


    So far, for me, this method is the most convenient for wrapping class components without breaking encapsulation.

    It can still be used as self-sufficient though.

     
    Alain Verleyen #:
    Not sure why you think it could be wrong

    By the fact that I only program in MQL😄

    Alain Verleyen #:
    The constructor is the initialization.

    Regarding the constructor, everising is clear. My question was about this line (member resolving without assignment operator):

    CCommonThings CSomeClass::common;
    Alain Verleyen #:
    it has nothing special ?

    This is a rarely seen construction in MQL. To learn programming, I used only S. Kovalyov's book, the MQL documentation and articles on this site. And nothing but this.

    I came up with something new for myself. But I did not find examples of using such a syntactic construct in MQL to validate this. That's why I asked you to confirm that the code is correct. And also because I'm paranoid and the fact that it works is not enough for me 😄