PLO. Fragen zur Anwendung - Seite 4

 
Yedelkin:

Frage. Ist es möglich, nach der Deklaration einer virtuellen Funktion mit einem bestimmten Satz von Parametern und Typen in einer übergeordneten Klasse die Anzahl und die Typen der Parameter der entsprechenden virtuellen Funktionen in nachgeordneten Klassen zu ändern?

Einerseits heißt es im Referenzhandbuch, dass "eine virtuelle Funktion in einer abgeleiteten Klasse ersetzt werden kann. Die Entscheidung, welche Funktionsdefinition für die virtuelle Funktion aufgerufen werden soll, wird dynamisch (zur Laufzeit) getroffen. Ein typischer Fall ist, wenn eine Basisklasse eine Funktion enthält und abgeleitete Klassen ihre eigenen Versionen dieser Funktion haben". Andererseits beziehen sich die im Referenzhandbuch angeführten Beispiele auf Fälle, in denen virtuelle Funktionen unterschiedliche Funktionsdefinitionskörper und nicht Funktionsdefinitionsköpfe haben.

So weit ich mich zurückerinnern kann, ist das möglich. Allerdings muss man bei der Art und Anzahl der Parameter sehr vorsichtig sein.

Sie müssen auch auf die Art der übergebenen Werte und die Standardwerte achten.

Der Einfachheit halber sind hier einige Beispiele aufgeführt.

Diese Variante wird den Zweck erfüllen.

boll MyFunction(int Param);
boll MyFunction(int Param1,int Param2);

Dies ist nicht der Fall (oder besser gesagt, vielleicht wird es funktionieren, aber mit einigen Fehlern und gewissen Vorbehalten).

//Ели второй параметр будет упущен, то компилятор может и не "понять" смысла всего задуманного
boll MyFunction(int Param);
boll MyFunction(int Param1,int Param2 = 0);
//Так тоже может не прокатить по причине совпадения типов у второго параметра
boll MyFunction(int Param1,color Param2);
boll MyFunction(int Param1,int Param2);

Genau das Gleiche passiert, wenn Sie Methoden innerhalb einer Klasse neu laden.

 
mql5:
Nur eine exakte Kopie der Definition, mit Ausnahme der Standardeinstellungen (die Standardeinstellungen können variieren, aber es ist besser, diese nicht zu verwenden)
Meinen Sie "nur eine exakte Kopie des Definitionsheaders "? Schließlich umfasst die Funktionsdefinition sowohl den Kopf als auch den Hauptteil. Die Körper in den Beispielen sind definitiv unterschiedlich.
 

Interessant, so wie ich es verstehe, sind Funktionsvirtualisierung und Funktionsüberladung leicht unterschiedliche Dinge. Undmql5 sagt, dass bei der Funktionsvirtualisierung eine Hardcopy des Funktionskopfes vorhanden sein sollte (ich berücksichtige keine Standardparameter).

 
Yedelkin:

Interessant, so wie ich es verstehe, sind Funktionsvirtualisierung und Funktionsüberladung ein bisschen unterschiedliche Dinge. Undmql5 sagt, dass in Funktionen Virtualisierung sollte es eine harte Kopie der Funktion Header (ich bin nicht unter Berücksichtigung der Standardparameter) sein.

> Frage. Ist es möglich, nach der Deklaration einer virtuellen Funktion mit einem bestimmten Satz von Parametern und deren Typen in einer übergeordneten Klasse die Anzahl und die Typen der Parameter der entsprechenden virtuellen Funktionen in den nachgeordneten Klassen zu ändern?

Wenn ich es richtig verstanden habe, muss das Kind die Funktionalität des Vorgängers überladen.

Ehrlich gesagt kann ich mich nicht daran erinnern, dass ich solche Dinge mit Virtual getan habe (ich glaube, ich habe es getan), aber die Aussage über die Überlastung ist wahr - ich habe diesen Fehler selbst einmal gemacht.

PS

Wenn alles richtig gemacht wird, kann die Anzahl der Parameter sowohl erhöht als auch verringert werden. Problematisch wird es, wenn die Anzahl der Parameter gleich bleibt, aber ihre Typen geändert werden...

 

Wie auch immer, ich habe dieses Beispiel skizziert:

class C_A             //родительский класс
{
 public:
 virtual double function(double a1, double a2, double a3) { return; }
}
class C_B : public C_A
{
 public:
 virtual double function(double a1, double a2, double a3) { return(a1);   }
}
class C_C : public C_A
{
 public:      
 virtual double function(double a1, double a2, double a3) { return(a2);   }
        double function(double a1, double a2)           { return(a1+a2); }
}
//где-то в программе объявляем указатель
C_A  *pointer;
int random=rand()%2;
   switch(random)
     {
      case 0: pointer=new C_B; break;
      case 1: pointer=new C_C; break;
     }

//вызываем виртуальный метод
   if(pointer!=NULL)
     {
      pointer.function(a1,a2,a3);
     }

Es stellt sich heraus, dass unabhängig davon, ob eine Funktionsmethode in der Klasse C_C überladen ist oder nicht, eine virtuelle Funktion mit nur drei Parametern aufgerufen werden kann - pointer.function(a1,a2,a3). Dementsprechend wird das Programm beim Aufruf der virtuellen Funktionen nie zu der Zwei-Parameter-Methode der Klasse C_C gelangen. Oder?

 
Yedelkin:

Wie auch immer, ich habe dieses Beispiel skizziert:

Es stellt sich heraus, dass unabhängig davon, ob eine Funktionsmethode in der Klasse C_C überladen ist oder nicht, eine virtuelle Funktion mit nur drei Parametern aufgerufen werden kann - pointer.function(a1,a2,a3). Dementsprechend wird das Programm beim Aufruf der virtuellen Funktionen nie zu der Zwei-Parameter-Methode der Klasse C_C gelangen. Oder?

Analysieren Sie, was das Programm durch Einfügen in Konstruktoren und Destruktoren druckt mit __FUNCTION__ Makro, wird es sehr nützlich sein.

Ich würde noch hinzufügen, dass man durch die Deklaration eines Zeigers auf eine Basisklasse einen "Tunnel" zu den Nachkommen durch die Basisklasse konstruiert. Somit sieht der Compiler nur die in der Basisklasse deklarierten Funktionen in den Nachfolgeklassen. Wenn Sie (auch innerhalb desselben Programms) ein Nachfolgeobjekt direkt deklarieren, sind alle Funktionen in diesem Objekt verfügbar.

class C_A             //родительский класс
{
 public:
 virtual double function(double a1, double a2, double a3) { return; }
}
class C_B : public C_A
{
 public:
 virtual double function(double a1, double a2, double a3) { return(a1);   }
}
class C_C : public C_A
{
 public:      
 virtual double function(double a1, double a2, double a3) { return(a2);   }
        double function(double a1, double a2)           { return(a1+a2); }
}
//где-то в программе объявляем указатель
C_A  *pointer;
int random=rand()%2;
   switch(random)
     {
      case 0: pointer=new C_B; break;
      case 1: pointer=new C_C; break;
//вызываем виртуальный метод
   if(pointer!=NULL)
     {
      pointer.function(a1,a2,a3);
     }
C_С  *new_pointer=new C_C;
      new_pointer.function(a1,a2);
 
Yedelkin:

Wie auch immer, ich habe dieses Beispiel skizziert:

Es stellt sich heraus, dass unabhängig davon, ob eine Funktionsmethode in der Klasse C_C überladen ist oder nicht, eine virtuelle Funktion mit nur drei Parametern aufgerufen werden kann - pointer.function(a1,a2,a3). Dementsprechend wird das Programm beim Aufruf der virtuellen Funktionen nie zu der Zwei-Parameter-Methode der Klasse C_C gelangen. Oder?

Aus eigener Erfahrung kann ich Ihnen empfehlen, den Code folgendermaßen zu verpacken

double function(double a1, double a2)            {return(a1+a2);}
double function(double a1, double a2, double a3) {return(a2);}

Sie können die beigefügte Datei als Beispiel und zur Unterhaltung ansehen.

Ich wollte mich nicht mit Zeigern und new herumschlagen, also habe ich die Arbeitsklasse einfach als Variable deklariert.

Der Expert Advisor generiert in gleichen Abständen eine Zufallszahl 0/1 und führt je nach Ergebnis eine von zwei Funktionen aus: MarketBuy / MarketSell.


Wenn Sie möchten, können Sie das so machen

bool MarketBuy(string SymbolTitle,double LotSize,double TP = 0.0,double SL = 0.0);
bool MarketSell(string SymbolTitle,double LotSize,double TP = 0.0,double SL = 0.0);

Aber in diesem Fall kann ein Fehler auftreten, weil ein Konflikt mit

bool MarketBuy(string SymbolTitle,double LotSize);
bool MarketSell(string SymbolTitle,double LotSize);


PS

Ich habe es von Hand gemacht, deshalb kann es einige Ungenauigkeiten geben.

Aber im Prinzip ist der Grundgedanke nachvollziehbar.

Dateien:
Forum.mq5  18 kb
 

Vielen Dank für die wertvollen Ratschläge und Hinweise! Ich werde sie auf jeden Fall nutzen, aber ich wünschte, ich hätte genug Zeit für Theorie und Praxis.

Interesting:

Aus meiner eigenen Erfahrung kann ich empfehlen, den Code so zu ergänzen

double function(double a1, double a2)            {return(a1+a2);}
double function(double a1, double a2, double a3) {return(a2);}
Warum auf diese Weise? Worin besteht die Falle?
 
Yedelkin:

Warum ist das so? Worin besteht die Falle?

Damit gab es früher ein Problem, glaube ich. Aber ich kann mich jetzt nicht mehr erinnern, welche es waren.

Wie auch immer, ich habe mich daran gewöhnt.

Normalerweise gibt es natürlich keinen Unterschied, zumindest in meinem Beispiel habe ich versucht, die Plätze zu tauschen, und es hat alles funktioniert...

 
Interesting:

Damit gab es früher ein Problem, glaube ich. Aber ich kann mich jetzt nicht mehr erinnern, welche es waren.

OK, auf jeden Fall werde ich das im Hinterkopf behalten.