타입캐스팅

숫자 유형 캐스팅

한 숫자 유형을 다른 숫자 유형으로 변환해야 하는 경우가 종종 있습니다. 일부 숫자 유형은 다른 숫자 유형으로 변환할 수 없습니다. 다음은 허용된 캐스팅 방식입니다:

가능한 타입캐스팅 방식

화살표가 있는 실선은 정보의 손실 없이 대부분 수행되는 변화를 나타냅니다. char 유형 대신 bool 유형을 사용(둘 다 메모리 1바이트 할애)할 수 있고, int 유형 대신 color 유형을 사용(4 바이트)할 수 있으며, long 유형 대신 datetime 유형을 사용(8 바이트)할 수 있습니다. 화살표로 표시된 4개의 파선 회색 선은 정밀도가 손실될 수 있는 변환을 나타냅니다. 예를 들어, 123456789 (int)와 같은 정수의 자릿수가 float로 나타낼 수 있는 자릿수보다 큽니다.

   int n=123456789;
   float f=n;    // f의 내용은 1.234567892E8 입니다
   Print("n = ",n,"   f = ",f);
   // result n= 123456789    f= 123456792.00000

float로 변환된 숫자는 순서는 같지만 정확도가 떨어집니다. 검은색 화살표와 달리 변환은 데이터 손실 가능성으로 이어질 수 있습니다. char와 uchar, short와 ushort, int와 uint, long과 ulong(양쪽으로의 변환) 사이의 변환은 데이터 손실을 초래할 수 있습니다.

부동 소수점 값을 정수 형식으로 변환하면 분수 부분이 항상 삭제됩니다. float을 가장 가까운 정수로 반올림하려면 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);
/*
  결과:
   round_g = 9
   math_round_g = 10
*/

이진 연산자에 의해 두 값이 결합되는 경우, 연산 실행 전에 하위 유형의 피연산자가 아래 체계에서 주어진 우선순위에 따라 상위 유형으로 변환됩니다.

이진 연산에 의한 연결 시 캐스팅

데이터 유형 char, uchar, short 및 ushort는 무조건 int 유형으로 변환됩니다.

예제:

   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가 int 유형이 높기 때문에 int 유형의 임시 변수로 변환됩니다. 정수 나눗셈 3/2의 결과로 int 타입의 값 1이 나옵니다.

첫 번째 예제의 두 번째 연산에서 두 번째 연산자는 상수 0.3이며, 이는 이중 유형이므로 첫 번째 연산 결과는 값이 1.0인 이중 유형의 임시 변수로 변환됩니다.

두 번째 예제에서 문자 유형 c1의 변수는 분할 연산의 두 번째 피연산자인 상수 2.0이 double 유형이기 때문에 더 이상 변환되지 않기 때문에 이중 유형의 임시 변수로 변환됩니다.

 

숫자 유형의 타입캐스팅

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);
// 결과:   (double)c1/2+0.3 = 1.80000000

분할 연산을 수행하기 전에 c1 변수가 double 유형에 명시적으로 캐스팅됩니다. 이제 첫 번째 피연산자를 변환한 결과 double 유형이 선택되었기 때문에 정수 상수 2가 double 유형의 값 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;         // 표현식은 double 형태로 캐스팅됩니다,
   Print("k = 1/2  ",k);  // 그렇다면 int의 대상 유형에 해당하며, 결과는 0입니다
 
   double d=1.0/2.0;    // 타입캐스팅 없음, 결과는 0.5
   Print("d = 1/2.0; ",d);
 
   double e=1/2.0;      // 표현식은 double 유형으로 캐스팅됩니다,
   Print("e = 1/2.0; ",e);// 대상 유형과 동일하며 결과는 0.5입니다
 
   double x=1/2;        // int 형식의 식이 double 타겟 typr으로 캐스팅됩니다,
   Print("x = 1/2; ",x);  // 결과는 0.0 입니다

long/ulong 유형을 double로 변환할 때 정수 값이 9223372036854774784보다 크거나 -9223372036854774784보다 작은 경우 정밀도가 손실될 수 있습니다.

void OnStart()
  {
   long l_max=LONG_MAX;
   long l_min=LONG_MIN+1;
//--- double로 캐스팅될 때 정확도가 손실되지 않는 최대 정수 값 정의
   while(l_max!=long((double)l_max))
      l_max--;
//--- double로 캐스팅될 때 정확도가 손실되지 않는 최저 정수 값 정의
   while(l_min!=long((double)l_min))
      l_min++;
//--- 정수 값에 대해 찾은 간격 도출  
   PrintFormat("정수 값을 double 로 캐스팅할 때는, 그것은 반드시 "
               "[%I64d, %I64d] 간격 이내여야 합니다",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)));
//--- 다음과 같은 결과를 얻습니다
// 정수 값을 double로 캐스팅할 경우 [-9223372036854774784, 92233720368547784] 구간 내에 있어야 합니다
// 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
  }

 

문자열 유형에 대한 타입캐스팅

문자열 유형은 단순 유형 중에서 우선 순위가 가장 높습니다. 따라서 작업의 피연산자 중 하나가 문자열 유형인 경우 두 번째 피연산자는 자동으로 문자열로 캐스팅됩니다. 문자열의 경우 단일 2단계 추가 작업이 가능합니다. 숫자 유형에 문자열을 명시적으로 캐스팅할 수 있습니다.

예제:

   string s1=1.0/8;            // 표현식은 double 유형으로 캐스팅됩니다,
   Print("s1 = 1.0/8; ",s1);     //  그러면 문자열 타입을 타겟으로 됩니다,
// 결과는 "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));

 

파생 클래스의 포인터에 대한 기본 클래스 포인터의 타입캐스팅

open generated 클래스의 개체는 해당 기본 클래스의 개체로도 볼 수 있습니다. 이것은 몇 가지 흥미로운 결과로 이어집니다. 예를 들어 단일 기본 클래스에서 생성된 서로 다른 클래스의 개체가 서로 크게 다를 수 있지만 기본 유형의 개체로 볼 때 연결된 목록(List)을 만들 수 있습니다. 그러나 기본 클래스 개체는 자동으로 파생 클래스의 개체가 아닙니다.

명시적 캐스팅을 사용하여 기본 클래스 포인터를 파생 클래스의 포인터로 변환할 수 있습니다. 그러나 이러한 변환의 허용 가능성에 대해 완전히 확신해야 합니다. 그렇지 않으면 심각한 런타임 오류가 발생하고 mql5 프로그램이 중지되기 때문입니다.

dynamic_cast 연산자를 사용한 동적 타입캐스팅 #

동적 타입캐스팅은 클래스에 대한 포인터에만 적용할 수 있는 dynamic_cast 연산자를 사용하여 수행됩니다. 유형 유효성 검사가 런타임에 수행됩니다. 즉, 컴파일러는 dynamic_cast 연산자를 사용할 때 형식 캐스팅에 적용된 데이터 형식을 확인하지 않습니다. 포인터가 실제 개체 유형이 아닌 데이터 유형으로 변환될 경우 결과는 NULL이 됩니다.

dynamic_cast <type-id> ( expression )

꺽쇠괄호의 type-id 매개변수는 이전에 정의된 클래스 유형을 가리켜야 합니다. C++와는 달리, 표현식n 피연산자 유형은 void를 제외한 모든 값을 가질 수 있습니다.

예제:

class CBar { };
class CFoo : public CBar { };
 
void OnStart()
  {
   CBar bar;    
//--- *foo 포인터에 *bar 포인터 유형을 동적 캐스팅할 수 있습니다.
   CFoo *foo = dynamic_cast<CFoo *>(&bar); // 치명적 오류 없음   
   Print(foo);                             // foo=NULL      
//--- Foo type 객체에 대한 Bar type 객체 참조를 명시적으로 캐스팅하려는 시도는 금지됩니다
   foo=(CFoo *)&bar;                       // 치명적 런타임 오류
   Print(foo);                             // 이 문자열은 실행되지 않습니다
  }

더 보기

데이터 타입