Il POF per gli scolari.

 

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

Questo argomento avrà alcuni esempi molto semplici di come usare l'OOP.

Le domande dei programmatori principianti sono benvenute. Quelli che vogliono veramente capire OOP.

"Ragazzi intelligenti" che pensano che io stia facendo qualcosa di sbagliato, iniziate i vostri thread e fatelo proprio lì. Nessuno ha bisogno di te qui.

Anche le controversie sulla necessità o l'inutilità dell'OOP sono irrilevanti qui.

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


1 Supponiamo di fare qualcosa con dei punti sul piano delle coordinate.

Supponiamo che ce ne siano solo 10.

Ci sono vari modi di immagazzinarli nella memoria.

Come questo:

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

O come questo:

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

O come questo:

double points[10][2];

Ma è molto più conveniente farlo in questo modo:

struct POINT
{
  double x;
  double y;
};

POINT points[10];

Abbiamo un nuovo tipo di dati, che è un punto su un piano.

Lavoriamo con un punto come entità separata.

Come esempio, scriviamo una funzione che calcola la distanza tra punti.

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 questo modo, OOP ci dà la possibilità di programmare in un linguaggio di compito.


Continuiamo...

 

2. Polimorfismo.

Supponiamo di avere questo codice:

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 questi tre casi, ci sono tre diverse funzioni di addizione dietro il segno più.

Questo si chiama polimorfismo.

L'OOP ci permette di estendere questa azione ad altri dati.

Per esempio, abbiamo una classe matrice. Si trova nel file matrix.mqh

Poi possiamo scrivere questo codice:

#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;

Qui l'OOP ci permette di dividere la responsabilità tra diverse parti del programma.

Quando scriviamo una classe matrice, non pensiamo a come verrà usata.

Ma quando è scritto e debuggato, lo usiamo in vari compiti senza pensare alle regole di addizione e moltiplicazione delle matrici.

Abbiamo appena messo + e *.


Per continuare ...

 

3. Funzioni virtuali.

Supponiamo di aver scritto diverse classi che rappresentano forme geometriche.

Tutti loro sono ereditati da una classe base Shape.

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();
};

Possiamo mettere tutte queste forme in un array se dichiariamo un array di puntatori alla classe base.

Shape* shapes[10];

Nella funzione Init() riempiamo questo 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;
    }
  }
}

La funzione OnPaint() viene chiamata quando dobbiamo visualizzare tutte le forme.

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

Facciamo un ciclo di tutte le forme e chiamiamo la funzione Draw() per ognuna di esse.

Per ogni forma chiamiamo la sua funzione che sa come disegnare quella particolare forma.

Questa è l'essenza delle funzioni virtuali.

E, naturalmente, non dimenticare di cancellarli alla fine.

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


Per continuare ...

 

No, loro (lo scolaro) non capirebbero. Soprattutto non una specie di matrice. Diranno: perché abbiamo bisogno di questo polimorfismo... una specie di polimorfismo? Tanto più che nell'emculus la sua efficienza è evidente solo se ci sono almeno 10 varianti. almeno 10 varianti.

Probabilmente, dovremmo iniziare con la possibilità di combinare funzioni e variabili - per sbarazzarci delle variabili globali e della confusione ad esse associata.

 
Dmitry Fedoseev:

No, loro (lo scolaro) non capirebbero. Soprattutto non una specie di matrice. Diranno: perché abbiamo bisogno di questo polimorfismo... una specie di polimorfismo? Tanto più che nell'emculus la sua efficienza è evidente solo se ci sono almeno 10 varianti. almeno 10 varianti.

Forse dovremmo iniziare con la possibilità di combinare funzioni e variabili - per sbarazzarci delle variabili globali e della confusione ad esse associata.

Credo che ))))

Personalmente, non ho ancora capito se questa OOP sia necessaria o meno. Non vedo vantaggi evidenti (a meno che non facciate lo stesso tipo di compiti, immagino). E non ho trovato un'introduzione semplice e chiara a questo argomento (forse perché non la stavo proprio cercando?) )))))))

 

4. incapsulamento.

Qui si sente spesso: "Perché abbiamo bisogno di fare membri di classe sepolti in OOP? Vogliamo che tutto sia aperto e accessibile ovunque".

Ma OOP non obbliga a rendere tutti i membri chiusi. Sta al programmatore decidere cosa deve essere nascosto e cosa no.

E di solito nascondono quelle cose che devono essere nascoste per ridurre la probabilità di corruzione accidentale dei dati.

Per esempio, abbiamo un pulsante, che può essere impostato su qualsiasi colore.

class ColorButton
{
   color myColor;

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

   color GetColor() const
   {
      return myColor;
   }

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

   void Update();
};

Potremmo rendere aperta la variabile myColor e cambiare il colore del pulsante in qualsiasi momento con una semplice assegnazione.

Ma l'assegnazione di questa variabile non farà sì che il pulsante venga ridisegnato immediatamente.

Quindi rendiamo privata la variabile myColor. E per cambiare il colore, chiamiamo la funzione SetColor().

Questa funzione, oltre ad assegnare una variabile, dice al sistema che il pulsante deve essere ridipinto.

In questa funzione, potete mettere qualsiasi altra azione necessaria.

La funzione GetColor() è usata per ottenere il colore del pulsante. La sua chiamata non è più costosa di un riferimento diretto alla variabile,

perché il compilatore può facilmente ottimizzarlo.

 
Koldun Zloy:

4. incapsulamento.


Ho ragione di supporre che in questo esempio si tratta, in gergo, degli stessi eteros e setor?

 
Roman:

Ho ragione di supporre che in questo esempio si tratta, in gergo, proprio di heters e setors?

Sì, è corretto.

 
Non ci sono getter e setter nell'emculus.
 
Dmitry Fedoseev:
Non ci sono getter e setter in emcool.

Questo non è determinato dal MQL, ma dal programmatore. Se lui vuole, lo faranno.

 
Ihor Herasko:

Questo non è determinato dal MQL, ma dal programmatore. Se lui vuole, lo faranno.

Il linguaggio di programmazione lo determina.

Motivazione: