Typecasting

Casting di Tipi Numerici

Spesso si verifica la necessità di convertire un tipo numerico in un altro. Non tutti i tipi numerici possono essere convertiti in altri. Ecco lo schema di casting consentito:

Schema di typecasting possibile

Le linee continue con le frecce indicano le modifiche che vengono eseguite quasi senza alcuna perdita di informazioni. Al posto del tipo char, può essere usato il tipo bool (entrambi prendono 1 byte di memoria), al posto del tipo int, può essere utilizzato il tipo color (4 byte), al posto del tipo long, può essere utilizzato il tipo datetime (prende 8 byte). Le quattro linee tratteggiate grigie, anch'esse a freccia, denotano conversioni, quando la perdita di precisione può verificarsi. Ad esempio, il numero di cifre nel numero intero pari a 123456789 (int) è superiore al numero di cifre che possono essere rappresentate da un float.

   int n=123456789;
   float f=n;    // il contenuto di f è uguale a 1.234567892E8
   Print("n = ",n,"   f = ",f);
   // risulta n= 123456789    f= 123456792.00000

Un numero convertito in float ha lo stesso ordine, ma è meno accurato. Le conversioni, inversamente alle frecce nere, possono essere eseguite con eventuale perdita di dati. Conversioni tra char ed uchar, short ed ushort, int ed uint, long ed ulong (conversioni da entrambe le parti), possono portare alla perdita di dati.

Come risultato di conversione di valori in virgola mobile verso il tipo intero, la parte frazionaria viene sempre eliminata. Se si desidera arrotondare un float al numero intero più vicino (che in molti casi è più utile), è necessario utilizzare MathRound ().

Esempio:

// --- Accelerazione gravitazionale
   double g=9.8;
   double round_g=(int)g;
   double math_round_g=MathRound(g);
   Print("round_g = ",round_g);
   Print("math_round_g = ",math_round_g);
/*
  Risultato:
   round_g = 9
   math_round_g = 10
*/

Se due valori vengono combinati da un operatore binario, prima dell'esecuzione dell'operazione l'operando di tipo inferiore viene convertito nel tipo superiore secondo la priorità data nel seguente schema:

Casting di collegamento da un'operazione binaria

I tipi di dati char, uchar, short, ed ushort incondizionatamente vengono convertiti nel tipo int.

Esempi:

   char   c1=3;
//--- Primo esempio
   double d2=c1/2+0.3;
   Print("c1/2 + 0.3 = ",d2);
// Risultato:   c1/2+0.3 = 1.3
 
//--- Secondo esempio
   d2=c1/2.0+0.3;
   Print("c1/2.0 + 0.3 = ",d2);
// Risultato:   c1/2.0+0.3 = 1.8

L'espressione calcolata si compone di due operazioni. Nel primo esempio, la variabile c1 del tipo char viene convertita in una variabile temporanea di tipo int, perché il secondo operando nell'operazione di divisione, la costante 2, è del tipo superiore int. Come risultato della divisione intera 3/2 si ottiene il valore 1, che è di tipo int.

Nella seconda operazione del primo esempio, il secondo operando è la costante 0.3, che è di tipo double, quindi il risultato della prima operazione viene convertito in una variabile temporanea di tipo double con il valore di 1.0 .

Nel secondo esempio la variabile di tipo char c1 viene convertita in una variabile temporanea di tipo double, perché il secondo operando nell'operazione di divisione, la costante 2.0, è di tipo double; non vengono effettuate altre conversioni.

 

Typecasting di Tipi Numerici

Nelle espressioni del linguaggio MQL5 entrambi il typecasting esplicito ed implicito, può essere utilizzato. Il typecasting esplicito è scritto come segue:

var_1 = (tipo)var_2;

Un risultato di un'espressione o di esecuzione di una funzione può essere utilizzato come variabile var_2. La registrazione funzionale del typecasting esplicito è anche possibile:

var_1 = tipo(var_2);

Consideriamo un typecasting esplicito sulla base del primo esempio.

//--- Terzo esempio
   double d2=(double)c1/2+0.3;
   Print("(double)c1/2 + 0.3 = ",d2);
// Risultato:   (double)c1/2+0.3 = 1.80000000

Prima che l'operazione di divisione venga eseguita, la variabile c1 è esplicitamente 'castata'(_* neologismo, da cast/casting) al tipo double. Ora il numero costante integer 2 è castato al valore 2.0 valore di tipo double, perché come risultato della conversione del primo operando ha preso il tipo double. Infatti, il typecasting esplicito è un'operazione unaria.

Inoltre, quando si cerca di castare i tipi, il risultato può andare oltre il range permissibile. In questo caso, avviene un troncamento. Ad esempio:

   char c;
   uchar u;
   c=400;
   u=400;
   Print("c = ",c); // Risultato c=-112
   Print("u = ",u); // Risultato u=144

Prima che le operazioni (ad eccezione di quelle assegnazione) vengano eseguite, i dati vengono convertiti nel tipo massima priorità. Prima che vengano eseguite le operazioni di assegnazione, i dati vengono castati nel tipo target(_*di destinazione).

Esempi:

   int    i=1/2;        // nessun casting del tipo, il risultato è 0
   Print("i = 1/2  ",i);
 
   int k=1/2.0;         // l'espressione viene castata al tipo double,
   Print("k = 1/2  ",k);  // quindi al tipo int, ed il risultato è 0
 
   double d=1.0/2.0;    // nessun casting del tipo, il risultato è 0.5
   Print("d = 1/2.0; ",d);
 
   double e=1/2.0;      // l'espressione è castata al tipo double,
   Print("e = 1/2.0; ",e);// che è lo stesso del tipo target, il risultato è 0.5
 
   double x=1/2;        // l'espressione di tipo int viene castata al target di tipo double,
   Print("x = 1/2; ",x);  // il risultato è 0.0

Durante la conversione di tipo long/ulong in double, la precisione può venir persa nel caso in cui il valore integer sia maggiore di 9223372036854774784 o minore di -9223372036854774784.

voidOnStart()
  {
   long l_max=LONG_MAX;
   long l_min=LONG_MIN+1;
//--- definisce il valore integer più alto, che non perde precisione quando viene castato in double
   while(l_max!=long((double)l_max))
      l_max--;
//--- definisce il valore integer più basso, che non perde precisione quando viene castato a double
   while(l_min!=long((double)l_min))
      l_min++;
//--- deriva l'intervallo trovato per valori interi  
   PrintFormat("Quando si casta un valore integer a double, dev'essere"
               "all'interno dell'intervallo [%I64d, %I64d] ",l_min,l_max);
//--- ora, vediamo cosa succede se il valore cade al di fuori di questo intervallo
   PrintFormat("l_max+1=%I64d, double(l_max+1)=%.f, ulong(double(l_max+1))=%I64d",
               l_max+1,double(l_max+1),long(double(l_max+1)));
   PrintFormat("l_min-1=%I64d, double(l_min-1)=%.f, ulong(double(l_min-1))=%I64d",
               l_min-1,double(l_min-1),long(double(l_min-1)));
//--- visualizza il seguente risultato
// Il casting di un valore integer a double, dovrebbe essere entro l'intervallo [-9223372036854774784, 9223372036854774784]
// l_max+1=9223372036854774785, double(l_max+1)=9223372036854774800, ulong(double(l_max+1))=9223372036854774784
// l_min-1=-9223372036854774785, double(l_min-1)=-9223372036854774800, ulong(double(l_min-1))=-9223372036854774784
  }

 

Typecasting per il tipo String

Il tipo stringa ha la priorità più alta tra i tipi semplici. Pertanto, se uno degli operandi di un'operazione è di tipo stringa, il secondo operando sarà castato in una stringa automaticamente. Si noti che per una stringa, è possibile una singola operazione di addizione diadica a doppio-luogo. Il casting esplicito di stringa in un qualsiasi tipo numerico, è consentito.

Esempi:

   string s1=1.0/8;            // l'espressione viene castata al tipo double,
   Print("s1 = 1.0/8; ",s1);     //  quindi nel tipo target stringa,
// il risultato è "0.12500000" (una stringa contenente 10 caratteri)
 
   string s2=NULL;             // deinizializzazione stringa 
   Print("s2 = NULL; ",s2);      // il risultato è una stringa vuota
   string s3="Ticket N"+12345; // l'espressione viene castata al tipo stringa
   Print("s3 = \"Ticket N\"+12345",s3);
 
   string str1="true";
   string str2="0,255,0";
   string str3="2009.06.01";
   string str4="1.2345e2";
   Print(bool(str1));
   Print(color(str2));
   Print(datetime(str3));
   Print(double(str4));

 

Typecasting di Puntatori di Classe Base a Puntatori di Classi Derivate

Oggetti di classi aperte generate possono anche essere visti come oggetti della classe base corrispondente. Questo porta ad alcune conseguenze interessanti. Per esempio, nonostante il fatto che gli oggetti di diverse classi, generati da una singola classe di base, possono differire significativamente l'uno dall'altro, possiamo creare una lista collegata (List) di essi, giacchè li vediamo come oggetti del tipo di base. Ma il contrario non è vero: gli oggetti della classe base non sono automaticamente gli oggetti di una classe derivata.

È possibile utilizzare il casting esplicito per convertire i puntatori della classe base in puntatori di una classe derivata. Ma si deve essere pienamente fiduciosi nella ammissibilità di tale trasformazione, perché altrimenti un errore runtime critico si verificherà e il programma MQL5 sarà interrotto.

Dynamic typecasting using dynamic_cast operator #

Dynamic typecasting is performed using dynamic_cast operator that can be applied only to pointers to classes. Type validation is performed at runtime. This means that the compiler does not check the data type applied for typecasting when dynamic_cast operator is used. If a pointer is converted to a data type which is not the actual type of an object, the result is NULL.

dynamic_cast <type-id> ( expression )

The type-id parameter in angle brackets should point to a previously defined class type. Unlike C++, expression operand type can be of any value except for void.

Example:

class CBar { };
class CFoo : public CBar { };
 
void OnStart()
  {
   CBar bar;    
//--- dynamic casting of *bar pointer type to *foo pointer is allowed
   CFoo *foo = dynamic_cast<CFoo *>(&bar); // no critical error   
   Print(foo);                             // foo=NULL      
//--- an attempt to explicitly cast a Bar type object reference to a Foo type object is forbidden
   foo=(CFoo *)&bar;                       // critical runtime error
   Print(foo);                             // this string is not executed
  }

Vedi anche

Tipi di Dati