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?
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.