사용자정의 유형

typedef 키워드(C++)를 사용하면 사용자 정의 데이터 유형을 만들 수 있습니다. 이렇게 하려면 기존 데이터 유형에 대해 새 데이터 유형 이름을 지정하기만 하면 됩니다. 새 데이터 유형이 생성되지 않았습니다. 대신 기존 유형의 새 이름이 정의됩니다. 사용자 정의 유형을 사용하면 응용 프로그램의 유연성이 향상됩니다. 때로는 대체 매크로(#define)를 사용하여 유형 정의 지침을 변경해도 충분합니다. 사용자 정의 유형을 사용하면 typedef를 사용하여 표준 데이터 유형에 사용자 정의 이름을 적용할 수 있으므로 코드 가독성도 향상됩니다. 사용자 정의 유형을 작성하기 위한 항목의 일반 형식:

   typedef type new_name;

여기서, 유형은 허용되는 모든 데이터 유형을 의미하며 new_name은 유형의 새 이름입니다. 새 이름은 기존 유형 이름에 대한 추가(대체가 아님)로만 설정됩니다. MQL5를 사용하면 typedef를 사용하여 함수에 대한 포인터를 만들 수 있습니다.

함수에 대한 포인터

함수에 대한 포인터는 일반적으로 다음 형식으로 정의됩니다

   typedef function_result_type (*Function_name_type)(list_of_input_parameters_types);

여기서 typedef 다음에 함수 시그니처(입력 파라미터의 수와 유형, 함수에 의해 반환되는 결과 유형)이 설정됩니다. 다음은 포인터를 만들고 함수에 적용하는 간단한 예입니다:

//--- 두 개의 int 매개변수를 수신하는 함수에 대한 포인터를 선언합니다
   typedef int (*TFunc)(int,int);
//--- TFunc는 유형이며 함수에 대한 변수 포인터를 선언할 수 있습니다
   TFunc func_ptr; // 함수에 대한 포인터
//--- TFunc 설명에 해당하는 함수를 선언합니다
   int sub(int x,int y) { return(x-y); }  // 수를 빼기
   int add(int x,int y) { return(x+y); }  // 두 수의 합
   int neg(int x)       { return(~x);  }  // 변수의 비트 반전
//--- func_ptr 변수는 함수 주소를 저장하여 나중에 선언할 수 있습니다
   func_ptr=sub;
   Print(func_ptr(10,5));
   func_ptr=add;
   Print(func_ptr(10,5));
   func_ptr=neg;           // 오류: neg에 int(int,int) 유형이 없습니다
   Print(func_ptr(10));    // 오류: 두 개의 매개 변수가 필요합니다

이 예제에서, func_ptr 변수는 subadd 함수를 수신할 수 있는데, 이는 int 유형의 두 인수가 함수에 대한 TFunc 포인터에 있기 때문입니다. 반대로 neg 함수는 시그니처가 다르기 때문에 func_ptr 포인터에 할당할 수 없습니다.

사용자 인터페이스에서 이벤트 모델 정렬

함수에 대한 포인터를 사용하면 사용자 인터페이스를 만들 때 이벤트 처리를 쉽게 만들 수 있습니다. CButton 섹션의 예를 사용하여 버튼을 만들고 버튼을 누르는 기능을 추가해 보겠습니다. 먼저 버튼을 눌러 호출할 TAction 함수에 대한 포인터를 정의하고 다음에 따라 세 가지 함수를 만듭니다: TAction 설명.

//--- 사용자 정의 함수 유형 만들기
typedef int(*TAction)(string,int);
//+------------------------------------------------------------------+
//|  파일 열기                                                        |
//+------------------------------------------------------------------+
int Open(string name,int id)
  {
   PrintFormat("%s 함수 호출됨 (name=%s id=%d)",__FUNCTION__,name,id);
   return(1);
  }
//+------------------------------------------------------------------+
//|  파일 저장                                                        |
//+------------------------------------------------------------------+
int Save(string name,int id)
  {
   PrintFormat("%s 함수 호출됨 (name=%s id=%d)",__FUNCTION__,name,id);
   return(2);
  }
//+------------------------------------------------------------------+
//|  파일 닫기                                                        |
//+------------------------------------------------------------------+
int Close(string name,int id)
  {
   PrintFormat("%s 함수 호출됨 (name=%s id=%d)",__FUNCTION__,name,id);
   return(3);
  }
 

그런 다음 CButton에서 MyButton 클래스를 만들고, 여기서 TAction 포인터를 함수에 추가해야 합니다.

//+------------------------------------------------------------------+
//| 이벤트 처리 기능으로 버튼 클래스 만들기                               |
//+------------------------------------------------------------------+
class MyButton: public CButton
  {
private:
   TAction           m_action;                    // 차트 이벤트 핸들러
public:
                     MyButton(void){}
                    ~MyButton(void){}
   //--- 이벤트 처리 함수에 대한 버튼 텍스트 및 포인터 지정하는 생성자
                     MyButton(string text, TAction act)
     {
      Text(text);
      m_action=act;
    }
   //--- OnEvent() 이벤트 처리기에서 호출된 사용자 지정 함수 설정
   void              SetAction(TAction act){m_action=act;}
   //--- 표준 차트 이벤트 처리기
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) override
     {      
      if(m_action!=NULL && lparam==Id())
        { 
         //--- 사용자 지정 m_action() 핸들러를 호출합니다. 
         m_action(sparam,(int)lparam);
         return(true);
        }
      else
      //--- CButton 부모 클래스에서 처리기를 호출한 결과를 반환합니다
         return(CButton::OnEvent(id,lparam,dparam,sparam));
    }
  };

CAppDialog에서 CControlsDialog 파생 클래스를 만들고 m_buttons 배열을 추가하는데 이는 MyButton 유형의 버튼과 다음을 저장하기 위함입니다: AddButton(MyButton &button)CreateButtons() methods.

//+------------------------------------------------------------------+
//| CControlsDialog 클래스                                            |
//| 목적: 어플리케이션 관리를 위한 그래픽 패널                            |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
  {
private:
   CArrayObj         m_buttons;                     // 버튼 배열
public:
                     CControlsDialog(void){};
                    ~CControlsDialog(void){};
   //--- 생성
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) override;
   //--- 버튼 추가
   bool              AddButton(MyButton &button){return(m_buttons.Add(GetPointer(button)));m_buttons.Sort();};
protected:
   //--- 버튼 생성 
   bool              CreateButtons(void);
  };
//+------------------------------------------------------------------+
//| 차트에 CControlsDialog 객체 생성                                   |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
   return(CreateButtons());
//---
  }
//+------------------------------------------------------------------+
//| 정의                                                              |
//+------------------------------------------------------------------+
//--- 들여쓰기 및 간격
#define INDENT_LEFT                         (11)      // 왼쪽에서 들여쓰기(경계선 너비 허용)
#define INDENT_TOP                          (11)      // 위에서 들여쓰기(경계선 너비 허용)
#define CONTROLS_GAP_X                      (5)       // 간격(X 좌표)
#define CONTROLS_GAP_Y                      (5)       // 간격(Y 좌표)
//--- 버튼용
#define BUTTON_WIDTH                        (100)     // 크기(X 좌표)
#define BUTTON_HEIGHT                       (20)      // 크기(Y 좌표)
//--- 표시 영역용
#define EDIT_HEIGHT                         (20)      // 크기(Y 좌표)
//+------------------------------------------------------------------+
//| CControlsDialog 패널에 버튼 작성 및 추가                            |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButtons(void)
  {
//--- 버튼 좌표 계산
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2;
   int y2=y1+BUTTON_HEIGHT;
//--- 버튼 개체와 함수에 대한 포인터 추가
   AddButton(new MyButton("Open",Open));
   AddButton(new MyButton("Save",Save));
   AddButton(new MyButton("Close",Close));
//--- 버튼을 그래픽으로 생성
   for(int i=0;i<m_buttons.Total();i++)
     {
      MyButton *b=(MyButton*)m_buttons.At(i);
      x1=INDENT_LEFT+i*(BUTTON_WIDTH+CONTROLS_GAP_X);
      x2=x1+BUTTON_WIDTH;
      if(!b.Create(m_chart_id,m_name+"bt"+b.Text(),m_subwin,x1,y1,x2,y2))
        {
         PrintFormat("버튼 생성 실패 %s %d",b.Text(),i);
         return(false);
        }
      //--- 각 버튼을 CControlsDialog 컨테이너에 추가
      if(!Add(b))
         return(false);
    }
//--- 성공
   return(true);
  }

이제 3개의 버튼이 있는 CControlsDialog 제어판을 사용하여 프로그램을 개발할 수 있습니다: 열기, 저장 및 닫기. 버튼을 클릭하면 TAction 포인터 형태의 해당 함수가 호출됩니다.

//--- 프로그램을 시작할 때 개체를 자동으로 만들려면 전역 수준에서 개체를 선언합니다
CControlsDialog MyDialog;
//+------------------------------------------------------------------+
//| Expert 초기화 함수                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 이제 차트에 개체를 만듭니다
   if(!MyDialog.Create(0,"Controls",0,40,40,380,344))
      return(INIT_FAILED);
//--- 어플리케이션 실행
   MyDialog.Run();
//--- 어플리케이션이 성공적으로 초기화됨
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert 초기화 해제 함수                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- 대화상자 제거
   MyDialog.Destroy(reason);
  }
//+------------------------------------------------------------------+
//| Expert 차트 이벤트 함수                                      |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // 이벤트 ID  
                  const long& lparam,   // long 타입의 이벤트 매개 변수
                  const double& dparam, // double 타입의 이벤트 매개 변수
                  const string& sparam) // 문자열 타입의 이벤트 매개 변수
  {
//--- 차트 이벤트에 대해 부모 클래스에서 핸들러를 호출(여기서는 CAppDialog 입니다).
   MyDialog.ChartEvent(id,lparam,dparam,sparam);
  }

실행된 응용 프로그램의 모양과 버튼 클릭 결과가 스크린샷에 제공됩니다.

panel_buttons

 

프로그램의 전체 소스 코드

//+------------------------------------------------------------------+
//|                                                Panel_Buttons.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
 
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property description "The panel with several CButton buttons"
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
//+------------------------------------------------------------------+
//| 정의                                                          |
//+------------------------------------------------------------------+
//--- 들여쓰기 및 간격
#define INDENT_LEFT                         (11)      // 왼쪽에서 들여쓰기(경계선 너비 허용)
#define INDENT_TOP                          (11)      // 위에서 들여쓰기(경계선 너비 허용)
#define CONTROLS_GAP_X                      (5)       // 간격(X 좌표)
#define CONTROLS_GAP_Y                      (5)       // 간격(Y 좌표)
//--- 버튼용
#define BUTTON_WIDTH                        (100)     // 크기(X 좌표)
#define BUTTON_HEIGHT                       (20)      // 크기(Y 좌표)
//--- 표시 영역용
#define EDIT_HEIGHT                         (20)      // 크기(Y 좌표)
 
//--- 사용자 정의 함수 유형 생성
typedef int(*TAction)(string,int);
//+------------------------------------------------------------------+
//|  파일 열기                                                  |
//+------------------------------------------------------------------+
int Open(string name,int id)
  {
   PrintFormat("%s 함수 호출됨 (name=%s id=%d)",__FUNCTION__,name,id);
   return(1);
  }
//+------------------------------------------------------------------+
//|  파일 저장                                                  |
//+------------------------------------------------------------------+
int Save(string name,int id)
  {
   PrintFormat("%s 함수 호출됨 (name=%s id=%d)",__FUNCTION__,name,id);
   return(2);
  }
//+------------------------------------------------------------------+
//|  파일 닫기                                                  |
//+------------------------------------------------------------------+
int Close(string name,int id)
  {
   PrintFormat("%s 함수 호출됨 (name=%s id=%d)",__FUNCTION__,name,id);
   return(3);
  }
//+------------------------------------------------------------------+
//| 이벤트 처리 기능으로 버튼 클래스 만들기      |
//+------------------------------------------------------------------+
class MyButton: public CButton
  {
private:
   TAction           m_action;                    // 차트 이벤트 핸들러
public:
                     MyButton(void){}
                    ~MyButton(void){}
   //--- 이벤트 처리 함수에 대한 버튼 텍스트 및 포인터 지정하는 생성자
                     MyButton(string text,TAction act)
     {
      Text(text);
      m_action=act;
    }
   //--- OnEvent() 이벤트 처리기에서 호출된 사용자 지정 함수 설정
   void              SetAction(TAction act){m_action=act;}
   //--- 표준 차트 이벤트 처리기
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) override
     {
      if(m_action!=NULL && lparam==Id())
        {
         //--- 커스텀 핸들러 호출
         m_action(sparam,(int)lparam);
         return(true);
        }
      else
      //--- CButton 부모 클래스에서 처리기를 호출한 결과를 반환합니다
         return(CButton::OnEvent(id,lparam,dparam,sparam));
    }
  };
//+------------------------------------------------------------------+
//| CControlsDialog 클래스                                            |
//| 목적: 어플리케이션 관리를 위한 그래픽 패널       |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
  {
private:
   CArrayObj         m_buttons;                     // 버튼 배열
public:
                     CControlsDialog(void){};
                    ~CControlsDialog(void){};
   //--- 생성
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) override;
   //--- 버튼 추가
   bool              AddButton(MyButton &button){return(m_buttons.Add(GetPointer(button)));m_buttons.Sort();};
protected:
   //--- 버튼 생성 
   bool              CreateButtons(void);
  };
//+------------------------------------------------------------------+
//| 차트에 CControlsDialog 객체 생성                   |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
   return(CreateButtons());
//---
  }
//+------------------------------------------------------------------+
//| CControlsDialog 패널에 버튼 작성 및 추가           |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButtons(void)
  {
//--- 버튼 좌표 계산
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2;
   int y2=y1+BUTTON_HEIGHT;
//--- 버튼 개체와 함수에 대한 포인터 추가
   AddButton(new MyButton("Open",Open));
   AddButton(new MyButton("Save",Save));
   AddButton(new MyButton("Close",Close));
//--- 버튼을 그래픽으로 생성
   for(int i=0;i<m_buttons.Total();i++)
     {
      MyButton *b=(MyButton*)m_buttons.At(i);
      x1=INDENT_LEFT+i*(BUTTON_WIDTH+CONTROLS_GAP_X);
      x2=x1+BUTTON_WIDTH;
      if(!b.Create(m_chart_id,m_name+"bt"+b.Text(),m_subwin,x1,y1,x2,y2))
        {
         PrintFormat("버튼 생성 실패 %s %d",b.Text(),i);
         return(false);
        }
      //--- 각 버튼을 CControlsDialog 컨테이너에 추가
      if(!Add(b))
         return(false);
    }
//--- 성공
   return(true);
  }
//--- 프로그램을 시작할 때 개체를 자동으로 만들려면 전역 수준에서 개체를 선언합니다
CControlsDialog MyDialog;
//+------------------------------------------------------------------+
//| Expert 초기화 함수                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 이제 차트에 개체를 만듭니다
   if(!MyDialog.Create(0,"Controls",0,40,40,380,344))
      return(INIT_FAILED);
//--- 어플리케이션 실행
   MyDialog.Run();
//--- 어플리케이션이 성공적으로 초기화됨
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert 초기화 해제 함수                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- 대화상자 제거
   MyDialog.Destroy(reason);
  }
//+------------------------------------------------------------------+
//| Expert 차트 이벤트 함수                                      |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // 이벤트 ID  
                  const long& lparam,   // long 타입의 이벤트 매개 변수
                  const double& dparam, // double 타입의 이벤트 매개 변수
                  const string& sparam) // 문자열 타입의 이벤트 매개 변수
  {
//--- 차트 이벤트에 대해 부모 클래스에서 핸들러를 호출(여기서는 CAppDialog 입니다).
   MyDialog.ChartEvent(id,lparam,dparam,sparam);
  }

 

더 보기

변수, 함수