Typecasting
类型转换
数值类型的转换
经常需要将一个数值类型转换为另一个数值类型。并非所有数值类型都可以进行转换。以下是允许的类型转换方案:

带箭头的实线表示几乎不会丢失信息地进行转换。可以使用bool类型代替char类型(两者都占用1字节的内存),使用color类型代替int类型(占用4字节),使用datetime代替long类型(占用8字节)。四条带箭头的灰色线表示可能发生精度损失的转换。例如,整数123456789的位数([int](../integer-types/char-short-int-and-long-types/#int))比[float](../real-types-double-float/)能表示的位数多。
int n=123456789;
float f=n; // the content of f is equal to 1.234567892E8
Print("n = ",n," f = ",f);
// result n= 123456789 f= 123456792.00000
转换为float的数字具有相同的小数位数,但精度较低。与黑色箭头不同,转换可能会丢失数据。char和uchar、short和ushort、int和uint、long和ulong之间的转换可能会导致数据丢失。
将浮点值转换为整数类型时,小数部分总是会被删除。如果要将float四舍五入到最接近的整数(在许多情况下更有用),应使用MathRound()。
示例:
//--- Gravitational acceleration
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);
/*
Result:
round_g = 9
math_round_g = 10
*/如果两个值通过二进制运算符组合,在执行操作之前,较低类型的操作数会根据以下方案中的优先级转换为较高类型:
char、uchar、short和ushort类型无条件地转换为int类型。
示例:
char c1=3;
//--- First example
double d2=c1/2+0.3;
Print("c1/2 + 0.3 = ",d2);
// Result: c1/2+0.3 = 1.3
//--- Second example
d2=c1/2.0+0.3;
Print("c1/2.0 + 0.3 = ",d2);
// Result: c1/2.0+0.3 = 1.8
计算表达式包含两个操作。在第一个示例中,char类型的变量c1被转换为int类型的临时变量,因为除法操作中的第二个操作数2是int类型。整数除法3/2的结果是1,属于int类型。
在第一个示例的第二个操作中,第二个操作数是0.3,属于double类型,因此第一个操作的结果被转换为double类型的临时变量1.0。
在第二个示例中,char类型的变量c1被转换为double类型的临时变量,因为除法操作中的第二个操作数2.0是double类型;不再进行其他转换。
数值类型的类型转换
在MQL4语言的表达式中,可以使用显式和隐式类型转换。显式类型转换的格式如下:
var_1 = (type)var_2;表达式或函数执行结果可以用作var_2变量。显式类型转换的函数风格表示法也是可能的:
var_1 = type(var_2);让我们考虑基于第一个示例的显式类型转换。
//--- Third example
double d2=(double)c1/2+0.3;
Print("(double)c1/2 + 0.3 = ",d2);
// Result: (double)c1/2+0.3 = 1.80000000
在执行除法操作之前,c1变量被显式转换为double类型。现在整数常量2被转换为double类型的2.0,因为第一个操作数在转换后变成了double类型。实际上,显式类型转换是一元操作。
此外,在尝试转换类型时,结果可能超出允许的范围。在这种情况下,会发生截断。例如:
char c;
uchar u;
c=400;
u=400;
Print("c = ",c); // Result c=-112
Print("u = ",u); // Result u=144
在执行操作之前(赋值操作除外),数据会被转换为最高优先级的类型。在执行赋值操作之前,数据会被转换为目标类型。
示例:
int i=1/2; // no types casting, the result is 0
Print("i = 1/2 ",i);
int k=1/2.0; // the expression is cast to the double type,
Print("k = 1/2 ",k); // then is to the target type of int, the result is 0
double d=1.0/2.0; // no types casting, the result is 0.5
Print("d = 1/2.0; ",d);
double e=1/2.0; // the expression is cast to the double type,
Print("e = 1/2.0; ",e);// that is the same as the target type, the result is 0.5
double x=1/2; // the expression of the int type is cast to the double target typr,
Print("x = 1/2; ",x); // the result is 0.0
当将long/ulong类型转换为double时,如果整数值大于9223372036854774784或小于-9223372036854774784,可能会丢失精度。
void OnStart()
{
long l_max=LONG_MAX;
long l_min=LONG_MIN+1;
//--- define the highest integer value, which does not lose accuracy when being cast to double
while(l_max!=long((double)l_max))
l_max--;
//--- define the lowest integer value, which does not lose accuracy when being cast to double
while(l_min!=long((double)l_min))
l_min++;
//--- derive the found interval for integer values
PrintFormat("When casting an integer value to double, it must be "
"within [%I64d, %I64d] interval",l_min,l_max);
//--- now, let's see what happens if the value falls out of this interval
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)));
//--- receive the following result
// When casting an integer value to double, it should be within [-9223372036854774784, 9223372036854774784] interval
// 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
}字符串类型的类型转换
在简单类型中,字符串类型具有最高优先级。因此,如果操作的一个操作数是字符串类型,第二个操作数将自动转换为字符串。请注意,对于字符串,只能进行一次二元两元加法操作。允许显式地将字符串转换为任何数值类型。
示例:
string s1=1.0/8; // the expression is cast to the double type,
Print("s1 = 1.0/8; ",s1); // then is to the target type of string,
// result is "0.12500000" (a string containing 10 characters)
string s2=NULL; // string deinitialization
Print("s2 = NULL; ",s2); // the result is an empty string
string s3="Ticket N"+12345; // the expression is cast to the string type
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));简单结构类型的类型转换
只有当两个结构的所有成员都是数值类型时,才能相互赋值简单结构类型的数据。在这种情况下,赋值操作的两个操作数(左右)必须是结构类型。不会进行逐成员转换,而是进行简单复制。如果结构的大小不同,则复制较小大小的字节数。这样,MQL4中未使用联合体得到了补偿。
示例:
struct str1
{
double d;
};
//---
struct str2
{
long l;
};
//---
struct str3
{
int low_part;
int high_part;
};
//---
struct str4
{
string s;
};
//+------------------------------------------------------------------+
void OnStart()
{
str1 s1;
str2 s2;
str3 s3;
str4 s4;
//---
s1.d=MathArcsin(2.0); // get the invalid number -1. # IND
s2=s1;
printf("1. %f %I64X",s1.d,s2.l);
//---
s3=s2;
printf("2. high part of long %.8X low part of long %.8X",
s3.high_part,s3.low_part);
//---
s4.s="some constant string";
s3=s4;
printf("3. buffer len is %d constant string address is 0x%.8X",
s3.low_part,s3.high_part);
}另一个示例说明了如何组织一个自定义函数,以接收color类型的RGB(红、绿、蓝)表示形式。创建两个大小相同但内容不同的结构。为了方便,让我们添加一个返回颜色RGB表示的字符串的函数。
#property script_show_inputs
input color testColor=clrBlue;// set color for testing
//--- structure for representing color as RGB
struct RGB
{
uchar blue; // blue component of color
uchar green; // green component of color
uchar red; // red component of color
uchar empty; // this byte is not used
string toString(); // function for receiving a string
};
//--- function for showing color as a string
string RGB::toString(void)
{
string out="("+(string)red+":"+(string)green+":"+(string)blue+")";
return out;
}
//--- structure for storing of the built-in color type
struct builtColor
{
color c;
};
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//--- a variable for storing in RGB
RGB colorRGB;
//--- variable for storing the color type
builtColor test;
test.c=testColor;
//--- casting two structures by copying contents
colorRGB=test;
Print("color ",test.c,"=",colorRGB.toString());
//---
}基类指针到派生类指针的类型转换
开放生成类的对象也可以被视为相应基类的对象。这带来了一些有趣的后果。例如,尽管由同一个基类生成的不同类对象可能彼此有很大差异,我们可以创建它们的链表(List),因为它们被视为基类型对象。但反之则不成立:基类对象不是派生类的自动对象。
可以使用显式类型转换将基类指针转换为派生类的指针。但必须完全确信这种转换是可行的,否则将发生严重的运行时错误,mql4程序将被停止。
使用dynamic_cast运算符进行动态类型转换
动态类型转换是使用只能应用于类指针的dynamic_cast运算符进行的。类型验证在运行时进行。这意味着当使用dynamic_cast运算符时,编译器不会检查用于类型转换的数据类型。如果指针被转换为不是对象实际类型的类型,结果将是NULL。
dynamic_cast <type-id> ( expression )尖括号中的type-id参数应指向先前定义的类类型。与C++不同,表达式操作数的类型可以是任何值,除了void。
示例:
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
}