mql4mt4

MQL4: How can we separate a class definition across files?


I would like to be able to split classes in MQL4 across files, i.e. into the definition in an include/.mqh file and an implementation in a library/.mq4 file. How do we do this - I keep getting compile errors ("'function_name' must have a body")?

E.g. I can take a subset of the code at https://docs.mql4.com/basis/oop/class_templates, and put the definition into a .mqh file:

#import "library.ex4"

//+------------------------------------------------------------------+
//| Class for a free access to an array element               |
//+------------------------------------------------------------------+
template<typename T>
class TSafeArray
  {
protected:
   T                 m_array[];
public:
   //--- operator for accessing the array element by index
   T                 operator[](int index);
  };

#import

and put the implementation into a .mq4 file (called library.mq4):

#property library

//+------------------------------------------------------------------+
//| Receiving an element by index                           |
//+------------------------------------------------------------------+
template<typename T>
T TSafeArray::operator[](int index)
  {
   static T invalid_value;
//---
   int max=ArraySize(m_array)-1;
   if(index<0 || index>=ArraySize(m_array))
     {
      PrintFormat("%s index %d is not in range (0-%d)!",__FUNCTION__,index,max);
      return(invalid_value);
     }
//---
   return(m_array[index]);
  }

This was asked previously, but the main answer put both definition and implementation into the .mqh file: What is the correct way to define MQL4 "#import of static class methods"?. Is there any way around this?


Solution

  • The best answer I found was pointed out by Ex Ovo Omnia at https://www.mql5.com/en/forum/157907#comment_3808727.

    Details are in the second section ("2. Export of the Hidden Implementation of a Class) at https://www.mql5.com/en/articles/362#expclass. Note that the files there work in MQL4 too if you change the extensions to .mq4 and update the #include / #import statements.

    In summary: define a base / parent class in the include file, then define and implement a derived / child class in the library file. In the expert file, a pointer to the base class can then be cast to a pointer of the derived class to make use of the hidden derived class methods.

    Thanks to Daniel Kniaz for his suggestion of the CArrayObj class (https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj). I found this is good if you wish to use arrays where all the elements are of the same type (e.g. an ArrayList-like object of integer elements) or if they follow certain predefined structures (e.g. CTrade) but not if your arrays have a custom structure of multiple different types.