类型转换

创建数字符

有必要把一组数字类型变化成另一种数字类型,但并非作用数字类型都能转换,下面是允许转换的模式:

可能的类型转换计划

箭头指明表示转换方向,期间没有任何损失信息,布尔型可以取代字符类型(只占用1字节),颜色型可以取代整型(4字节),日期时间型可以取代长型(占用8字节)。四条灰色虚线,也带有箭头,在精确度缺失时,表示转化。例如,与123456789相等的整数字 (int) 就高于浮点型 表示的数字。

   int n=123456789;
   float f=n;    //  f 内容同于 1.234567892E8
   Print("n = ",n,"   f = ",f);
   // 结果 n= 123456789    f= 123456792.00000

 

转化成浮点型的数字有同样的命令,但是精确度比较低。与黑色箭头不同的是,转化允许部分数据丢失。字符型和无符号字符型间的转化,短整型和无符号短整型间的转化,整型及无符号整型的转化,长整型和无符号长整型的转化(双向转化),都可能导致数据丢失。

因此浮点值转化成整数型的结果就是,经常删除小数部分。如果想把浮点转成最近的整数(任何情况下都很有用),应该使用 MathRound()

示例:

//--- 重力加速度
   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   c1=3;
//--- 第一示例
   double d2=c1/2+0.3;
   Print("c1/2 + 0.3 = ",d2);
// 结果:   c1/2+0.3 = 1.3
 
//--- 第二示例
   d2=c1/2.0+0.3;
   Print("c1/2.0 + 0.3 = ",d2);
// 结果:   c1/2.0+0.3 = 1.8

计算的表达式由两种操作构成。示例一,字符型变量c1转化成整型临时变量,因为除法操作中的第二运算对象,常量2,是高类型整型。因此3/2的整数我们取整数值,1。

在示例一中的第二步中,第二运算对象是常量0.3,双精度型,那么结果就是第一运算对象转化成1.0双精度型临时变量。

示例二中,字符型c1变量转化成双精度型临时变量,因为除法操作的第二运算对象,常量2.0,是双精度型;无进一步转化。

 

数型类型转换

在MQL5语言表达式中,使用明确和含蓄两种类型转换。明确类型转换如下:

var_1 = (type)var_2;

表达式或者函数执行的结果可用作 var_2变量。明确类型转换的函数记录也可以如此:

var_1 = type(var_2);

基于第一示例,考虑下明确类型转换。

//--- 第三示例
   double d2=(double)c1/2+0.3;
   Print("(double)c1/2 + 0.3 = ",d2);
// 结果:   (双精度)c1/2+0.3 = 1.80000000

做除法前,c1变量明确为双精度型。现在整型常量2,转换成双精度型2.0,因为转换造成第一运算对象成为双精度型。实际上,明确类型转换时是一种一元运算操作。

此外,当尝试转换类型时,结果可能超出允许范围内。在这个情况下,容易发生截断。例如:

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

在运算完成之前(除了数据已被定义的),数据会根据优先级被转换。当定义数据的操作完成前,数据会转换成被定义的数据类型。

示例:

   int    i=1/2;        // 无类型转换, 结果是 0
   Print("i = 1/2  ",i);
 
   int k=1/2.0;         // 表达式转换到双精度型,
   Print("k = 1/2  ",k);  // 那么就是到整型的目标类型,结果是0
 
   double d=1.0/2.0;    // 无类型转换,结果是 0.5
   Print("d = 1/2.0; ",d);
 
   double e=1/2.0;      // 表达式转换到双精度型,
   Print("e = 1/2.0; ",e);// 同于目标类型,结果为0.5
 
   double x=1/2;        // 整型表达式转换到双精度目标类型,
   Print("x = 1/2; ",x);  // 结果是 0.0

如果整型值大于9223372036854774784或小于-9223372036854774784,当从长整型/无符号长整型转化到双精度型时,精度可能会丢失。

void OnStart()
  {
   long l_max=LONG_MAX;
   long l_min=LONG_MIN+1;
//--- 定义最高整型值,在转换到双精度时不会丢失精度。
   while(l_max!=long((double)l_max))
      l_max--;
//--- 定义最低整型值,在转换到双精度时不会丢失精度。
   while(l_min!=long((double)l_min))
      l_min++;
//--- 派生发现的整型值区间
   PrintFormat("When casting an integer value to double, it must be "
               "within [%I64d, %I64d] interval",l_min,l_max);
//--- 现在,让我们看看如果值跌落该区间会发生什么
   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)));
//--- 收到下面结果
// 当将整型值转换到双精度型时,它应该在[-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
  }

 

字符串类型转换

字符串类型是几种简单类型中的最高级别。因此,如果操作的运算对象之一为字符串,第二运算对象自动转换成字符串。注意的是,对于字符串,添加独立二元操作是可以的。允许任何字符串明确转换成数字类型。

示例:

   string s1=1.0/8;            // 表达式转换到双精度型,
   Print("s1 = 1.0/8; ",s1);     //  那么就是到字符串的目标类型,
// 结果 is "0.12500000" (包括10个字符的字符串)
 
   string s2=NULL;             // 字符串无法初始化
   Print("s2 = NULL; ",s2);      // 结果是空值字符串
   string s3="Ticket N"+12345; // 表达式转换到字符串类型
   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));

 

基本类指针到派生类指针的类型转换

打开生成分类目标也可以看做相关基本类目标。这将导致一些有趣的影响。例如,即使一个基本类生成的不同类目标彼此明显不同,我们仍然可以创建它们的链接列表(List),因为我们将它们全部视为基本类型的目标。但是反过来却不可以:基本类目标不能自动成为派生类的目标。

您可以使用明确转换,将基本类指针转化成派生类指针。但是对这种转化要有足够的资格,因为否则的话,会导致危险的运行错误而mql5程序会停止。

动态类型转换使用 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;    
//--- 允许动态转换* bar 指针类型 * foo 指针
   CFoo *foo = dynamic_cast<CFoo *>(&bar); // 不重要的错误   
   Print(foo);                             // foo=NULL      
//--- 禁止尝试引用Foo 类型对象明确转换Bar 类型对象
   foo=(CFoo *)&bar;                       // 关键的运行时间错误
   Print(foo);                             // 这个字符串不被执行
  }

另见

数据类型