The EOP for schoolchildren.

 

========================================================================================================================

This topic will provide some oh-so-simple examples of how to use OOP.

Questions from novice programmers are welcome. Those who really want to understand OOP.

"Smart guys" who think I'm doing something wrong, start your own threads and do it right there. No one needs you here.

Disputes about necessity and uselessness of OOP are also irrelevant here.

========================================================================================================================


1 Suppose we are doing something with points on the coordinate plane.

Suppose there are only 10 of them.

There are various ways of storing them in memory.

Like this:

double x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6, x7, y7, x8, y8, x9, y9, x10, y10;

Or like this:

double pointsX[10];
double pointsY[10];

Or like this:

double points[10][2];

But it's much more convenient to do it this way:

struct POINT
{
  double x;
  double y;
};

POINT points[10];

We have a new data type, which is a point on a plane.

We work with a point as a separate entity.

As an example, we write a function that calculates the distance between points.

POINT p1, p2;

double D = Distance( p1, p2 );

double Distance( const POINT& p1, const POINT& p2 )
{
  double dx = p1.x - p2.x;
  double dy = p1.y - p2.y;
  return sqrt( dx * dx + dy * dy );
}

In this way, OOP gives us the ability to program in a task language.


We continue...

 

2. Polymorphism.

Suppose we have this code:

int iA = 1;
int iB = 3;

double dA = 4.5;
double dB = 3.14;

string sA = "abcd";
string sB = "efgh";

int iC = iA + iB;

double dC = dA + dB;

string sC = sA + sB;

In these three cases, there are three different addition functions behind the plus sign.

This is called polymorphism.

OOP allows us to extend this action to other data.

For example, we have a matrix class. It is located in file matrix.mqh

Then we can write this code:

#include <matrix.mqh>

matrix< double > mA( 2, 2 );
mA[0][0] = 1.0;
mA[0][1] = 2.0;
mA[1][0] = 3.0;
mA[1][1] = 4.0;

matrix< double > mB( 2, 2 );
mB[0][0] = 5.0;
mB[0][1] = 6.0;
mB[1][0] = 7.0;
mB[1][1] = 8.0;

matrix< double > mC = mA + mB;

Here OOP allows us to divide responsibility between different parts of the program.

When we write a matrix class, we don't think about how it will be used.

But when it is written and debugged, we use it in various tasks without thinking about the rules of matrix addition and multiplication.

We just put + and *.


To be continued ...

 

3. Virtual functions.

Suppose we have written several classes representing geometric shapes.

All of them are inherited from one Shape base class.

class Shape
{
public:
  Shape();

  virtual void Draw() = 0;
};

class Circle : public Shape
{
public:
  Circle();

  virtual void Draw();
};

class Rectangle : public Shape
{
public:
  Rectangle();

  virtual void Draw();
};

class Star : public Shape
{
public:
  Star();

  virtual void Draw();
};

We can put all these shapes in one array if we declare an array of pointers to the base class.

Shape* shapes[10];

In the Init() function we fill this array.

void Init()
{
  for( int i = 0; i < 10; i++ )
  {
    switch( i % 3 ){
      case 0:
        shapes[i] = new Circle();
        break;
      case 1:
        shapes[i] = new Rectangle();
        break;
      case 2:
        shapes[i] = new Star();
        break;
    }
  }
}

The OnPaint() function is called when we need to display all the shapes.

void OnPaint()
{
   for( int i = 0; i < 10; i++ )
   {
      shapes[i].Draw();
   }
}

We loop through all shapes and call the Draw() function for each one.

For each shape we call its own function that knows how to draw that particular shape.

This is the essence of virtual functions.

And of course, do not forget to delete them at the end.

void OnDeinit()
{
  for( int i = 0; i < 10; i++ ){
    delete shapes[i];
  }
}


To continue ...

 

Nah, they (the schoolboy) wouldn't understand. Especially not some kind of matrix. They will say: why do we need this polymorphism... some kind of polymorphism? The more so, that in the emculus its efficiency is apparent only if there are at least 10 variants. at least 10 variants.

Probably, we should start with the possibility to combine functions and variables - to get rid of global variables and confusion associated with them.

 
Dmitry Fedoseev:

Nah, they (the schoolboy) wouldn't understand. Especially not some kind of matrix. They will say: why do we need this polymorphism... some kind of polymorphism? The more so, that in the emculus its efficiency is apparent only if there are at least 10 variants. at least 10 variants.

Maybe we should start with the possibility to combine functions and variables - to get rid of global variables and the confusion associated with them.

I guess ))))

Personally, I still don't understand whether this OOP is necessary or not. I don't see any obvious advantages (unless you're doing the same kind of tasks, I guess). And I haven't found a simple and clear introduction to this topic (maybe because I wasn't really looking for it?) )))))))

 

4. encapsulation.

One can often hear here: "Why do we need to make buried class members in OOP? We want everything to be open and accessible everywhere."

But OOP does not force to make all the members closed. It is up to the programmer to decide what must be hidden and what must not.

And usually they hide those things which must be hidden to reduce the probability of accidental data corruption.

For instance, we have a button, which can be set to any colour.

class ColorButton
{
   color myColor;

public:
   ColorButton( color clr ) : myColor( clr ){}

   color GetColor() const
   {
      return myColor;
   }

   void SetColor( color clr )
   {
      myColor = clr;
      Update();
   }

   void Update();
};

We could make variable myColor open and change the button's colour at any time by a simple assignment.

But assigning this variable will not cause the button to redraw immediately.

So we make the myColor variable private. And to change the colour, we call the SetColor() function.

This function, besides assigning a variable, tells the system that the button should be repainted.

In this function, you can put any other necessary actions.

The GetColor() function is used to get the colour of the button. Its call is not more expensive than a direct reference to the variable,

because the compiler can easily optimize this.

 
Koldun Zloy:

4. encapsulation.


Am I correct in assuming that in this example this is, in slang, the very heteros and setors ?

 
Roman:

Am I correct in assuming that in this example it is, in slang, the very heters and setors ?

Yes. That's correct.

 
There are no getters and setters in the emculus.
 
Dmitry Fedoseev:
There are no getters and setters in emcool.

This is not determined by the MQL, but by the programmer. If he wants to, they will.

 
Ihor Herasko:

This is not determined by the MQL, but by the programmer. If he wants to, they will.

The programming language determines that.

Reason: