Das EOP für Schulkinder.

 

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

In diesem Thema werden einige sehr einfache Beispiele für die Verwendung von OOP vorgestellt.

Fragen von unerfahrenen Programmierern sind willkommen. Diejenigen, die OOP wirklich verstehen wollen.

"Klugscheißer", die denken, dass ich etwas falsch mache, sollten ihre eigenen Threads eröffnen und es genau dort tun. Niemand braucht Sie hier.

Streitigkeiten über die Notwendigkeit oder Unbrauchbarkeit von OOP sind hier ebenfalls irrelevant.

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


1 Nehmen wir an, wir machen etwas mit Punkten auf der Koordinatenebene.

Angenommen, es gibt nur 10 von ihnen.

Es gibt verschiedene Möglichkeiten, sie im Speicher abzulegen.

Zum Beispiel so:

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

Oder so:

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

Oder so:

double points[10][2];

Aber es ist viel bequemer, es auf diese Weise zu tun:

struct POINT
{
  double x;
  double y;
};

POINT points[10];

Wir haben einen neuen Datentyp, der ein Punkt auf einer Ebene ist.

Wir arbeiten mit einem Punkt als eigenständige Einheit.

Als Beispiel schreiben wir eine Funktion, die den Abstand zwischen Punkten berechnet.

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

Auf diese Weise gibt uns OOP die Möglichkeit, in einer Aufgabensprache zu programmieren.


Wir fahren fort...

 

2. Polymorphismus.

Nehmen wir an, wir haben diesen 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 diesen drei Fällen verbergen sich hinter dem Pluszeichen drei verschiedene Additionsfunktionen.

Dies wird als Polymorphismus bezeichnet.

OOP ermöglicht es uns, diese Aktion auf andere Daten auszuweiten.

Wir haben zum Beispiel eine Matrixklasse. Sie befindet sich in der Datei matrix.mqh

Dann können wir diesen Code schreiben:

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

Hier ermöglicht OOP die Aufteilung der Verantwortung zwischen verschiedenen Teilen des Programms.

Wenn wir eine Matrixklasse schreiben, denken wir nicht darüber nach, wie sie verwendet werden soll.

Aber wenn sie geschrieben und getestet ist, verwenden wir sie bei verschiedenen Aufgaben, ohne an die Regeln der Matrixaddition und -multiplikation zu denken.

Wir setzen einfach + und * ein.


Fortsetzung folgt ...

 

3. Virtuelle Funktionen.

Angenommen, wir haben mehrere Klassen geschrieben, die geometrische Formen darstellen.

Sie alle werden von einer Shape-Basisklasse geerbt.

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

Wir können alle diese Formen in einem Array unterbringen, wenn wir ein Array mit Zeigern auf die Basisklasse deklarieren.

Shape* shapes[10];

Mit der Funktion Init() füllen wir dieses 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;
    }
  }
}

Die Funktion OnPaint() wird aufgerufen, wenn wir alle Formen anzeigen müssen.

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

Wir gehen in einer Schleife durch alle Formen und rufen die Funktion Draw() für jede einzelne auf.

Für jede Form rufen wir eine eigene Funktion auf, die weiß, wie man diese bestimmte Form zeichnet.

Dies ist das Wesen der virtuellen Funktionen.

Und vergessen Sie natürlich nicht, sie am Ende zu löschen.

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


Um fortzufahren ...

 

Nein, das würden sie (die Schüler) nicht verstehen. Schon gar nicht in einer Art Matrix. Sie werden sagen: Warum brauchen wir diesen Polymorphismus... eine Art von Polymorphismus? Zumal im Emculus seine Effizienz erst bei mindestens 10 Varianten sichtbar wird. mindestens 10 Varianten.

Wahrscheinlich sollten wir mit der Möglichkeit beginnen, Funktionen und Variablen zu kombinieren - um die globalen Variablen und die damit verbundene Verwirrung loszuwerden.

 
Dmitry Fedoseev:

Nein, das würden sie (die Schüler) nicht verstehen. Schon gar nicht in einer Art Matrix. Sie werden sagen: Warum brauchen wir diesen Polymorphismus... eine Art von Polymorphismus? Zumal im Emculus seine Effizienz erst bei mindestens 10 Varianten sichtbar wird. mindestens 10 Varianten.

Vielleicht sollten wir mit der Möglichkeit beginnen, Funktionen und Variablen zu kombinieren - um globale Variablen und die damit verbundene Verwirrung loszuwerden.

Ich schätze, ))))

Ich persönlich verstehe immer noch nicht, ob dieses OOP notwendig ist oder nicht. Ich sehe keine offensichtlichen Vorteile (es sei denn, Sie erledigen dieselbe Art von Aufgaben, nehme ich an). Und ich habe keine einfache und klare Einführung zu diesem Thema gefunden (vielleicht weil ich nicht wirklich danach gesucht habe?) )))))))

 

4. Einkapselung.

Man kann hier oft hören: "Warum müssen wir in der OOP vergrabene Klassenmitglieder machen? Wir wollen, dass alles offen und überall zugänglich ist".

Aber OOP zwingt nicht dazu, alle Mitglieder geschlossen zu machen. Es ist Sache des Programmierers, zu entscheiden, was versteckt werden muss und was nicht.

Und in der Regel verstecken sie die Dinge, die versteckt werden müssen, um die Wahrscheinlichkeit einer versehentlichen Datenbeschädigung zu verringern.

Wir haben zum Beispiel eine Schaltfläche, die auf eine beliebige Farbe eingestellt werden kann.

class ColorButton
{
   color myColor;

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

   color GetColor() const
   {
      return myColor;
   }

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

   void Update();
};

Wir könnten die Variable myColor öffnen und die Farbe der Schaltfläche jederzeit durch eine einfache Zuweisung ändern.

Die Zuweisung dieser Variablen bewirkt jedoch nicht, dass die Schaltfläche sofort neu gezeichnet wird.

Wir machen also die Variable myColor privat. Und um die Farbe zu ändern, rufen wir die Funktion SetColor() auf.

Diese Funktion weist nicht nur eine Variable zu, sondern teilt dem System auch mit, dass die Schaltfläche neu gezeichnet werden soll.

In dieser Funktion können Sie alle anderen notwendigen Aktionen eingeben.

Die Funktion GetColor() wird verwendet, um die Farbe der Schaltfläche zu ermitteln. Sein Aufruf ist nicht teurer als ein direkter Verweis auf die Variable,

weil der Compiler dies leicht optimieren kann.

 
Koldun Zloy:

4. Einkapselung.


Gehe ich recht in der Annahme, dass in diesem Beispiel die Heteros und Setors gemeint sind?

 
Roman:

Gehe ich recht in der Annahme, dass es sich in diesem Beispiel, umgangssprachlich, um die Heters und Setors selbst handelt?

Ja, das ist richtig.

 
Es gibt keine Getter und Setter im Emculus.
 
Dmitry Fedoseev:
In emcool gibt es keine Getter und Setter.

Dies wird nicht durch die MMS, sondern durch den Programmierer bestimmt. Wenn er es will, werden sie es tun.

 
Ihor Herasko:

Dies wird nicht durch die MMS, sondern durch den Programmierer bestimmt. Wenn er es will, werden sie es tun.

Die Programmiersprache bestimmt das.