Conversão de Tipo (Typecasting)

Conversão de Tipos Numéricos

Frequentemente surge a necessidade de converter um tipo numérico em outro. Nem todos os tipos numéricos podem ser convertidos em outro. Aqui está o esquema de conversão permitida:

Esquema de possíveis tipos de conversão

Linhas sólidas com setas indicam mudanças que são realizadas quase sem nenhuma perda de informação. Ao invés do tipo char, o tipo bool pode ser usado (ambos ocupam 1 byte de memória), ao invés do tipo int, o tipo color pode ser usado (4 bytes), ao invés do tipo long, datetime pode ser usado (ocupa 8 bytes). As quatro linhas cinzentas tracejadas, também com setas, denotam conversão em que a perda de precisão pode ocorrer. Por exemplo, o número de algarismos em um inteiro igual a 123456789 (int) é maior que o número de algarismos que podem ser representados por um float.

   int n=123456789;
   float f=n;    // o conteúdo de f é igual a 1.234567892E8
   Print("n = ",n,"   f = ",f);
   // resultado n= 123456789    f= 123456792.00000

O número convertido em float tem a mesma ordem de grandeza, mas é menos preciso. Conversões, no sentido contrário das setas pretas, podem ser realizadas com possível perda de dados. Conversões entre char e uchar, short e ushort, int e uint, long e ulong (conversões para ambos os lados), podem levar a perda de dados.

Como resultado da conversão de valores de ponto flutuante para o tipo inteiro, a parte fracionária é sempre excluída. Se você quiser arredondar um float para o inteiro mais próximo (que em muitos casos é mais útil), você deve usar MathRound().

Exemplo:

//--- Aceleração gravitacional
   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);
/*
  Resultado:
   round_g = 9
   math_round_g = 10
*/

Se dois valores são combinados por um operador binário, antes da execução da operação, o operando do tipo mais baixo é convertido para o do tipo mais alto, em concordância com a prioridade dada no esquema abaixo:

Conversão na ligação por um operador binário

Os tipos de dados char, uchar, short, e ushort incondicionalmente são convertido para o tipo int.

Exemplos:

   char   c1=3;
//--- Primeiro exemplo
   double d2=c1/2+0.3;
   Print("c1/2 + 0.3 = ",d2);
// Resultado:   c1/2+0.3 = 1.3
 
//--- Segundo exemplo
   d2=c1/2.0+0.3;
   Print("c1/2.0 + 0.3 = ",d2);
// Resultado:   c1/2.0+0.3 = 1.8

A expressão calculada consiste de duas operações. No primeiro exemplo, a variável c1 do tipo char é convertida para uma variável temporária do tipo int, porque o segundo operando da operação de divisão, a constante 2, é do tipo mais alto, int. Como resultado da divisão de inteiros, 3/2, nós obtemos o valor 1, que é do tipo inteiro.

Na segunda operação do primeiro exemplo, o segundo operando é a constante 0.3, que é do tipo double, então o resultado da primeira operação é convertido em uma variável temporária para o tipo double com o valor 1.0.

No segundo exemplo, a variável c1 do tipo char é convertida para uma variável temporária do tipo double, porque o segundo operando da operação de divisão, a constante 2.0, é do tipo double; nenhuma conversão adicional é feita.

 

Conversão de Tipos Numéricos

Nas expressões da linguagem MQL5 tanto conversão explicita quanto implícita podem ser usadas. A conversão explícita é escrita da seguinte forma:

var_1 = (type)var_2;

Uma expressão ou resultado de execução de uma função podem ficar no lugar da variável var_2. A notação funcional de uma conversão explícita é também possível:

var_1 = type(var_2);

Vamos considerar uma conversão explícita com base no primeiro exemplo.

//--- Terceiro exemplo
   double d2=(double)c1/2+0.3;
   Print("(double)c1/2 + 0.3 = ",d2);
// Resultado:   (double)c1/2+0.3 = 1.80000000

Antes da operação de divisão ser realizada, a variável c1 é explicitamente convertida para o tipo double. Agora a constante inteira 2 é convertida no valor 2.0 do tipo double, pois o resultado da conversão do primeiro operando assumiu o tipo double. De fato, a conversão explícita é uma operação unária.

Além disso, quanto tentar converter tipos, o resultado pode ir além da faixa permitida. Neste caso, o truncamento ocorre. Por exemplo:

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

Antes de operações (exceto operações de atribuição) serem realizadas, os dados são convertidos para o tipo de máxima prioridade. Antes de operações de atribuição serem realizadas, os dados são convertidos para o tipo destino.

Exemplos:

   int    i=1/2;        // nenhuma conversão, o resultado é 0
   Print("i = 1/2  ",i);
 
   int k=1/2.0;         // a expressão é convertida para o tipo double,
   Print("k = 1/2  ",k);  // então é convertido para o tipo destino, o resultado é 0
 
   double d=1.0/2.0;    // nenhuma conversão de tipos, o resultado é 0.5
   Print("d = 1/2.0; ",d);
 
   double e=1/2.0;      // a expressão é convertida para o tipo double,
   Print("e = 1/2.0; ",e);// que é o mesmo do tipo destino, o resultado é 0.5
 
   double x=1/2;        // a expressão do tipo inteiro é convertido para o tipo destino double,
   Print("x = 1/2; ",x);  // o resultado é 0.0

Ao converter o tipo long/ulong em double, a precisão pode ser perdida caso o valor inteiro seja maior do que 223372036854774784 ou menor do que -9223372036854774784.

void OnStart()
  {
   long l_max=LONG_MAX;
   long l_min=LONG_MIN+1;
//--- definir o valor inteiro maior, que não perde a precisão ao ser lançado para double
   while(l_max!=long((double)l_max))
      l_max--;
//--- definir o valor inteiro menor, que não perde a precisão ao ser lançado para double
   while(l_min!=long((double)l_min))
      l_min++;
//--- resulta no intervalo encontrado para valores inteiro  
   PrintFormat("Ao converter um valor inteiro para double, ele deve ser "
               "dentro [%I64d, %I64d] do intervalo",l_min,l_max);
//--- agora, vamos ver o que acontece se o valor fica fora deste intervalo
   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)));
//--- receber o seguinte resultado
// Ao converter um valor integer para double, ele deve estar dentro do intervalo [-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
  }

 

Conversão para o tipo String

O tipo string tem a mais alta prioridade entre os tipos simples. Portanto, se um dos operandos de uma operação é do tipo string, o segundo operando será convertido para uma string automaticamente. Observe que para uma string, uma única operação de dois-lugares diádicos de adição é possível. A conversão explicita de string para qualquer tipo numérico é permitida.

Exemplos:

   string s1=1.0/8;            // a expressão é convertida para o tipo double,
   Print("s1 = 1.0/8; ",s1);     //  daí é convertida para o tipo string,
// resultado é "0.12500000" (uma string contém 10 caracteres)
 
   string s2=NULL;             // string desinicialização
   Print("s2 = NULL; ",s2);      // o resultado é uma string vazia
   string s3="Ticket N"+12345; // a expressão é convertida para o tipo string
   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));

 

Conversão de Ponteiros de Classe Base para Ponteiros de Classes Derivadas

Objetos de classe derivada podem ser vistos como objetos da correspondente classe base. Isso leva a algumas conseqüências interessantes. Por exemplo, apesar do fato que objetos de diferentes classes, gerados a partir de uma única classe base, poderem diferir significativamente um do outro, podemos criar uma lista ligada (List) com eles, já que vemos eles como objetos do tipo base. Mas o inverso não é verdade: objetos da classe base não são automaticamente objetos da classe derivada.

Você pode usar a conversão explicita para converter ponteiros da classe base para ponteiros da classe derivada. Mas você deve estar totalmente confiante na admissibilidade de tal transformação, porque senão um erro crítico de execução ocorrerá e o programa MQL5 será interrompido.

Conversão dinâmica de tipos  usando o operador dynamic_cast #

Existe a possibilidade de realizar uma conversão dinâmica de tipos usando o operador dynamic_cast, ele pode ser aplicado apenas para ponteiros de classes. Além disso, a revisão dos tipos é realizada quando o programa está em execução. Isto significa que, ao usar operador compilador dynamic_cast não se verifica o tipo de dados usado para a conversão. Se for levada a cabo conversão do apontador para o tipo de dados que não é um tipo real de objeto, o resultado  será  o valor NULL.

dynamic_cast <type-id> ( expression )

O parâmetro type-id em colchetes angulares deve ser o ponteiro um tipo de classe definido anteriormente. O tipo de operando expression (ao contrário de C++) pode ser qualquer um, exceto void.

Exemplo:

class CBar { };
class CFoo : public CBar { };
 
void OnStart()
  {
   CBar bar;    
//--- permitida a conversão dinâmica do tipo de ponteiro *bar para o ponteiro *foo
   CFoo *foo = dynamic_cast<CFoo *>(&bar); // não acontecerão erros críticos de execução   
   Print(foo);                             // foo=NULL      
//--- restringida a tentativa de clara conversão dos enlaces do objeto do tipo Bar para o objeto de tipo Foo
   foo=(CFoo *)&bar;                       // acontecerá um erro crítico de execução
   Print(foo);                             // esta linha não será executada
  }

Também Veja

Tipos de Dados