• binary +,-,/,*,%,<<,>>,==,!=,<,>,<=,>=,=,+=,-=,/=,*=,%=,&=,|=,^=,<<=,>>=,&&,||,&,|,^
• unary +,-,++,--,!,~
• assignment operator =
• indexing operator []

Operation overloading allows the use of the operating notation (written in the form of simple expressions) for complex objects - structures and classes. Writing expressions using overloaded operations simplifies the view of the source code, because a more complex implementation is hidden.

For example, consider complex numbers, which consist of real and imaginary parts. They are widely used in mathematics. The MQL5 language has no data type to represent complex numbers, but it is possible to create a new data type in the form of a structure or class. Declare the complex structure and define four methods that implement four arithmetic operations:

 //+------------------------------------------------------------------+ //| A structure for operations with complex numbers                  | //+------------------------------------------------------------------+ struct complex   {    double            re; // Real part    double            im; // Imaginary part    //--- Constructors                      complex():re(0.0),im(0.0) {  }                      complex(const double r):re(r),im(0.0) {  }                      complex(const double r,const double i):re(r),im(i) {  }                      complex(const complex &o):re(o.re),im(o.im) { }    //--- Arithmetic operations    complex           Add(const complex &l,const complex &r) const;  // Addition    complex           Sub(const complex &l,const complex &r) const;  // Subtraction    complex           Mul(const complex &l,const complex &r) const;  // Multiplication    complex           Div(const complex &l,const complex &r) const;  // Division   };

Now, in our code we can declare variables representing complex numbers, and work with them.

For example:

 void OnStart()   { //--- Declare and initialize variables of a complex type    complex a(2,4),b(-4,-2);    PrintFormat("a=%.2f+i*%.2f,   b=%.2f+i*%.2f",a.re,a.im,b.re,b.im); //--- Sum up two numbers    complex z;    z=a.Add(a,b);    PrintFormat("a+b=%.2f+i*%.2f",z.re,z.im); //--- Multiply two numbers    z=a.Mul(a,b);    PrintFormat("a*b=%.2f+i*%.2f",z.re,z.im); //--- Divide two numbers    z=a.Div(a,b);    PrintFormat("a/b=%.2f+i*%.2f",z.re,z.im); //---   }

But it would be more convenient to use usual operators "+", "-", "*" and "/" for ordinary arithmetic operations with complex numbers.

Keyword operator is used for defining a member function that performs type conversion. Unary and binary operations for class object variables can be overloaded as non-static member functions. They implicitly act on the class object.

Most binary operations can be overloaded like regular functions that take one or both arguments as a class variable or a pointer to an object of this class. For our type complex, overloading in the declaration will look like this:

 //--- Operators    complex operator+(const complex &r) const { return(Add(this,r)); }    complex operator-(const complex &r) const { return(Sub(this,r)); }    complex operator*(const complex &r) const { return(Mul(this,r)); }    complex operator/(const complex &r) const { return(Div(this,r)); }

The full example of the script:

 //+------------------------------------------------------------------+ //| Script program start function                                    | //+------------------------------------------------------------------+ void OnStart()   { //--- Declare and initialize variables of type complex    complex a(2,4),b(-4,-2);    PrintFormat("a=%.2f+i*%.2f,   b=%.2f+i*%.2f",a.re,a.im,b.re,b.im);    //a.re=5;    //a.im=1;    //b.re=-1;    //b.im=-5; //--- Sum up two numbers    complex z=a+b;    PrintFormat("a+b=%.2f+i*%.2f",z.re,z.im); //--- Multiply two numbers      z=a*b;    PrintFormat("a*b=%.2f+i*%.2f",z.re,z.im); //--- Divide two numbers    z=a/b;    PrintFormat("a/b=%.2f+i*%.2f",z.re,z.im); //---   } //+------------------------------------------------------------------+ //| A structure for operations with complex numbers                  | //+------------------------------------------------------------------+ struct complex   {    double            re; // Real part    double            im; // Imaginary part    //--- Constructors                      complex():re(0.0),im(0.0) {  }                      complex(const double r):re(r),im(0.0) {  }                      complex(const double r,const double i):re(r),im(i) {  }                      complex(const complex &o):re(o.re),im(o.im) { }    //--- Arithmetic operations    complex           Add(const complex &l,const complex &r) const;  // Addition    complex           Sub(const complex &l,const complex &r) const;  // Subtraction    complex           Mul(const complex &l,const complex &r) const;  // Multiplication    complex           Div(const complex &l,const complex &r) const;  // Division    //--- Binary operators    complex operator+(const complex &r) const { return(Add(this,r)); }    complex operator-(const complex &r) const { return(Sub(this,r)); }    complex operator*(const complex &r) const { return(Mul(this,r)); }    complex operator/(const complex &r) const { return(Div(this,r)); }   }; //+------------------------------------------------------------------+ //| Addition                                                         | //+------------------------------------------------------------------+ complex complex::Add(const complex &l,const complex &r) const   {    complex res; //---    res.re=l.re+r.re;    res.im=l.im+r.im; //--- Result    return res;   } //+------------------------------------------------------------------+ //| Subtraction                                                      | //+------------------------------------------------------------------+ complex complex::Sub(const complex &l,const complex &r) const   {    complex res; //---    res.re=l.re-r.re;    res.im=l.im-r.im; //--- Result    return res;   } //+------------------------------------------------------------------+ //| Multiplication                                                   | //+------------------------------------------------------------------+ complex complex::Mul(const complex &l,const complex &r) const   {    complex res; //---    res.re=l.re*r.re-l.im*r.im;    res.im=l.re*r.im+l.im*r.re; //--- Result    return res;   } //+------------------------------------------------------------------+ //| Division                                                         | //+------------------------------------------------------------------+ complex complex::Div(const complex &l,const complex &r) const   { //--- Empty complex number    complex res(EMPTY_VALUE,EMPTY_VALUE); //--- Check for zero    if(r.re==0 && r.im==0)      {       Print(__FUNCTION__+": number is zero");       return(res);      } //--- Auxiliary variables    double e;    double f; //--- Selecting calculation variant    if(MathAbs(r.im)

Most unary operations for classes can be overloaded as ordinary functions that accept a single class object argument or a pointer to it. Add overloading of unary operations "-" and "!".

 //+------------------------------------------------------------------+ //| A structure for operations with complex numbers                  | //+------------------------------------------------------------------+ struct complex   {    double            re;       // Real part    double            im;       // Imaginary part ...    //--- Unary operators     complex operator-()  const; // Unary minus    bool    operator!()  const; // Negation   }; ... //+------------------------------------------------------------------+ //| Overloading the "unary minus" operator                           | //+------------------------------------------------------------------+ complex complex::operator-() const   {    complex res; //---    res.re=-re;    res.im=-im; //--- Result    return res;   } //+------------------------------------------------------------------+ //| Overloading the "logical negation" operator                      | //+------------------------------------------------------------------+ bool complex::operator!() const   { //--- Are the real and imaginary parts of the complex number equal to zero?    return (re!=0 && im!=0);   }

Now we can check the value of a complex number for zero and get a negative value:

 //+------------------------------------------------------------------+ //| Script program start function                                    | //+------------------------------------------------------------------+ void OnStart()   { //--- Declare and initialize variables of type complex    complex a(2,4),b(-4,-2);    PrintFormat("a=%.2f+i*%.2f,   b=%.2f+i*%.2f",a.re,a.im,b.re,b.im); //--- Divide the two numbers    complex z=a/b;    PrintFormat("a/b=%.2f+i*%.2f",z.re,z.im); //--- A complex number is equal to zero by default (in the default constructor re==0 and im==0)    complex zero;    Print("!zero=",!zero); //--- Assign a negative value    zero=-z;    PrintFormat("z=%.2f+i*%.2f,  zero=%.2f+i*%.2f",z.re,z.im, zero.re,zero.im);    PrintFormat("-zero=%.2f+i*%.2f",-zero.re,-zero.im); //--- Check for zero once again       Print("!zero=",!zero); //---   }

Note that we did not have to overload the assignment operator "=", as structures of simple types can be directly copied one into each other. Thus, we can now write a code for calculations involving complex numbers in the usual manner.

Overloading of the indexing operator allows to obtain the values of the arrays enclosed in an object, in a simple and familiar way, and it also contributes to a better readability of the source code. For example, we need to provide access to a symbol in the string at the specified position. A string in MQL5 is a separate type string, which is not an array of symbols, but with the help of an overloaded indexing operation we can provide a simple and transparent work in the generated CString class:

 //+------------------------------------------------------------------+ //| Class to access symbols in string as in array of symbols         | //+------------------------------------------------------------------+ class CString   {    string            m_string;    public:                      CString(string str=NULL):m_string(str) { }    ushort operator[] (int x) { return(StringGetCharacter(m_string,x)); }   }; //+------------------------------------------------------------------+ //| Script program start function                                    | //+------------------------------------------------------------------+ void OnStart()     { //--- An array for receiving symbols from a string    int     x[]={ 19,4,18,19,27,14,15,4,17,0,19,14,17,27,26,28,27,5,14,                  17,27,2,11,0,18,18,27,29,30,19,17,8,13,6 };    CString str("abcdefghijklmnopqrstuvwxyz[ ]CS");    string  res; //--- Make up a phrase using symbols from the str variable    for(int i=0,n=ArraySize(x);i

Another example of overloading of the indexing operation is operations with matrices. The matrix represents a two-dimensional dynamic array, the array size is not defined in advance. Therefore, you cannot declare an array of form array[][] without specifying the size of the second dimension, and then pass this array as a parameter. A possible solution is a special class CMatrix, which contains an array of CRow class objects.