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:

Name:  casting.png
Views: 73
Size:  7.7 KB

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:

Name:  casting5.png
Views: 74
Size:  1.6 KB

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
}