객체 지향 프로그래밍의 기초
소개
객체 지향 프로그래밍 (OOP) 학습을 시작하려는 사람은 누구나 다형성, 캡슐화, 오버로드 및상속과 같은 단어를 처음 접했다고 가정할 수 있습니다. 누군가 미리 만들어진 클래스를보고 그 다형성이나 캡슐화가 실제로 어디에 있는지 알아내려고 했을 수도 있습니다. 대부분 이것은 OOP 학습 과정의 끝일 수 있습니다.
사실 모든 것이 보기보다 훨씬 간단합니다. OOP를 사용하기 위해 이 단어가 무엇을 의미하는지 알 필요가 없습니다. - OOP 기능만 사용할 수 있으며 이름이 무엇인지 알지 못합니다. 그래도 이 글을 읽을 모든 분들이 OOP 사용법을 배우는 것뿐만 아니라 이 단어들의 의미도 분명히 해주셨으면 합니다.
함수 라이브러리 생성
OOP의 첫 번째이자 가장 간단한 응용 프로그램은 자주 사용하는 함수의 라이브러리를 만드는 것입니다. 물론 이러한 함수를 포함 파일 (mqh)에 간단히 저장할 수 있습니다. 함수가 필요한 경우 파일을 포함하고 이 함수를 호출하면 됩니다. 그러나 충분히 오래 프로그래밍하면 엄청난 양의 함수를 수집 할 수 있으므로 이름과 목적을 기억하기 어려울 수 있습니다.
여러 파일에서 함수를 수집하여 목적에 따라 범주로 분할할 수 있습니다. 예를 들어 배열 작업 기능, 문자열 작업 기능, 순서 계산 기능 등이 있습니다. 마지막 문장에서 "category"라는 단어는 "classes"라는 단어로 대체 될 수 있습니다. 의미는 동일하게 유지되지만 객체 지향 프로그래밍이라는 주제에 더 가까이 다가갈 것입니다.
따라서 함수는 배열로 작업할 함수 클래스, 문자열로 작업할 함수 클래스, 순서를 세는 함수 클래스 등으로 나눌 수 있습니다. "클래스"라는 단어는 기본 개념이기 때문에 OOP의 주제에 더 가까워집니다. 다양한 참고서, 사전 및 백과 사전 (예 : Wikipedia)에서 "프로그래밍 클래스"가 무엇인지 검색 할 수 있습니다.
아마도 첫인상은 "다형성", "캡슐화"등의 단어와 거의 같을 것입니다. 이 순간 '클래스'라는 이름은 함수와 변수의 집합을 의미합니다. 클래스를 사용하여 라이브러리를 만드는 경우 - 처리된 데이터 유형 또는 처리 된 객체 유형 (배열, 문자열, 순서)별로 그룹화 된 함수 및 변수 집합입니다.
프로그램의 프로그램
포럼에 대해 유사한 질문이 많이있었습니다 (그리고 앞으로도 있을 것입니다) - Expert Advisor로부터 스크립트를 호출하는 방법은 무엇입니까? 타사 도구를 사용하지 않고 스크립트 코드를 Expert Advisor 코드에 배치하여이 작업을 수행합니다. 사실 어려운 작업은 아니지만 스크립트는 EA와 동일한 이름의 변수와 함수를 사용할 수 있으므로 스크립트 코드를 조정해야 합니다. 변경 사항은 복잡하지는 않지만 볼륨면에서 상당 할 것입니다.
이 스크립트를 별도의 독립 프로그램으로 부르면 좋을 것입니다! 스크립트를 클래스로 프로그래밍 한 다음이 클래스를 사용하면 가능합니다. 작업량은 몇 줄의 코드로만 증가합니다. 이 경우 클래스는 처리된 데이터의 유형이 아니라 목적에 따라 함수를 결합합니다. 예: 보류중인 주문을 삭제하는 클래스, 포지션을 열거 나 주문하는 클래스, 그래픽 개체로 작업 할 클래스 등.
클래스의 중요한 특징은 그것이 위치한 공간과 구별된다는 것입니다. 이 클래스는 운영 체제에서 실행되는 프로그램과 같습니다. 여러 프로그램이 동시에 실행될 수 있지만 서로 독립적으로 실행될 수 있습니다. 따라서 클래스는 위치하는 공간과 구별되므로 "프로그램의 프로그램"이라고 할 수 있습니다.
수업의 모양과 느낌
클래스 생성은 class라는 단어로 시작하고 클래스 이름이 뒤 따르고 클래스의 전체 코드가 중괄호 안에 배치됩니다.
class CName { // Here is the entire code of the class };주의! 닫는 중괄호 뒤에 세미콜론을 넣는 것을 잊지 마십시오.
표시 및 숨김 (캡슐화)
어떤 프로그램을 수강하면 다양한 기능이 포함되어 있음을 알고 있습니다. 이러한 기능은 주 및 보조의 두 가지 유형으로 나눌 수 있습니다. 주요 기능은 프로그램이 실제로 구성되는 기능입니다. 이러한 기능에는 사용자가 알 필요가 없는 다른 많은 기능이 필요할 수 있습니다. 예를 들어, 클라이언트 터미널에서 포지션 트레이더를 열려면 새 주문 대화 상자를 열고 손절매 및 이익 실현의 볼륨, 값을 입력 한 다음 "매수"또는 "매도"를 클릭해야 합니다.
그러나 버튼을 클릭하고 포지션을 여는 것 사이에 실제로 일어나는 일은 터미널 개발자만이 확실히 알 수 있습니다. 터미널이 볼륨 위치 확인, 손절매 및 이익 실현 값 확인, 네트워크 연결 확인 등 많은 작업을 한다고 가정할 수 있습니다. 많은 절차가 숨겨져 있거나, 즉 캡슐화 됩니다. 마찬가지로 클래스에서 코드를 조각 (함수 및 변수)으로 분할 할 수 있습니다. 일부는 클래스를 사용할 때 사용할 수 있고 일부는 숨겨집니다.
캡슐화 수준은 private, protected 및 public 키워드를 사용하여 정의됩니다. 보호 와 비공개의 차이점은 잠시 후에 고려되지만 먼저 비공개 및 공개 키워드에 대해 살펴 보겠습니다. 따라서 간단한 클래스 템플릿은 다음과 같은 형식을 취합니다.
class CName { private: // Variables and functions available only inside the class public: // Variables and functions available outside the class };OOP를 활용하기에 충분합니다. Expert Advisor (스크립트 또는 인디케이터)에서 직접 코드를 작성하는 대신 먼저 클래스를 만든 다음이 클래스의 모든 내용을 작성합니다. 다음으로 실제 예에서 private 및 public 섹션의 차이점을 고려합니다.
라이브러리 생성 예
위에 제시된 클래스 템플릿을 사용하여 함수 라이브러리를 만들 수 있습니다. 배열로 작업할 클래스를 만들어 보겠습니다. 배열을 사용할 때 발생할 수있는 가장 일반적인 작업은 배열에 새 요소를 추가하고 지정된 값을 가진 요소가 배열에 존재하지 않는 경우 새 요소를 추가하는 것입니다.
배열에 요소를 추가하는 함수의 이름을 AddToEnd()로 지정하고 배열에 고유 요소를 추가하는 함수를 AddToEndIfNotExists()로 지정합니다. AddToEndIfNotExists() 함수에서 먼저 추가된 요소가 이미 배열에 존재하는지 확인하고 그렇지 않은 경우 AddToEnd() 함수를 사용합니다. 요소가 이미 배열에 존재하는지 확인하는 함수는 보조로 간주되므로 private 섹션과 다른 모든 함수 - public 섹션에 배치합니다. 결과적으로 다음과 같은 클래스를 얻게됩니다.
class CLibArray { private: // Check if an element with required value exists in array int Find(int &aArray[],int aValue) { for(int i=0; i<ArraySize(aArray); i++) { if(aArray[i]==aValue) { return(i); // Element exists, return index of element } } return(-1); // No such element, return -1 } public: // Add to end of array void AddToEnd(int &aArray[],int aValue) { int m_size=ArraySize(aArray); ArrayResize(aArray,m_size+1); aArray[m_size]=aValue; } // Add to end of array if there is no such value in array already void AddToEndIfNotExistss(int &aArray[],int aValue) { if(Find(aArray,aValue)==-1) { AddToEnd(aArray,aValue); } } };
로딩 클래스
클래스를 사용하려면 로드 해야 합니다. 클래스가 별도의 파일에 있는 경우 이 파일을 포함해야 합니다.
#include <OOP_CLibArray_1.mqh>
이 클래스를 로드합니다. 클래스 로딩은 변수 선언과 유사합니다.
CLibArray ar;
먼저 클래스의 이름이 나오고 그 다음이 인스턴스를 참조하는 포인터의 이름이 옵니다. 로드 후 클래스는 객체가 됩니다. 객체의 기능을 사용하려면 포인터 이름, 점 및 함수 이름을 입력하십시오. 점을 입력하면 클래스 함수 드롭 다운 목록이 열립니다 (그림 1).
그림 1. 기능 목록
드롭 다운 목록 덕분에 함수 이름을 기억할 필요가 없습니다. 이름 목록을 탐색하고 함수의 용도를 기억할 수 있습니다. 이것은 단순히 파일에서 함수를 수집하는 것과 달리 클래스를 사용하여 라이브러리를 만드는 가장 큰 장점입니다.
함수 수집의 경우 함수 이름의 첫 글자 몇 개를 입력하면 드롭 다운 목록에 포함된 모든 라이브러리의 모든 함수가 표시되고 클래스를 사용하면 지정된 클래스와 관련된 함수만 표시됩니다. 또한 Find() 함수는 나열되지 않습니다. 이것이 private 섹션과 public 섹션의 차이점입니다. 이 함수는 private 섹션에 작성되어 있으므로 사용할 수 없습니다.
다양한 데이터 유형에 대한 범용 라이브러리 만들기 (오버로드)
이 시점에서 라이브러리에는 int 유형의 배열에서만 작동하는 함수가 포함되어 있습니다. int 유형 배열 외에도 다음 유형의 배열에 라이브러리 함수를 적용해야 할 수 있습니다. uint, long, ulong 등 다른 데이터 유형의 배열의 경우 자체 함수를 작성해야 합니다. 그러나 이러한 함수에 다른 이름을 지정할 필요는 없습니다. 전달된 매개 변수 유형 또는 매개 변수 집합 (이 예에서는 매개 변수 유형에 따라)에 따라 올바른 함수가 자동으로 선택됩니다. long 유형의 배열로 작업하는 함수로 클래스를 보완 해 보겠습니다.
class CLibArray { private: // Для int. Check if an element with required value exists in array int Find(int &aArray[],int aValue) { for(int i=0; i<ArraySize(aArray); i++) { if(aArray[i]==aValue) { return(i); // Element exists, return index of element } } return(-1); // No such element, return -1 } // For long. Check if an element with required value exists in array int Find(long &aArray[],long aValue) { for(int i=0; i<ArraySize(aArray); i++) { if(aArray[i]==aValue) { return(i); // Element exists, return index of element } } return(-1); // No such element, return -1 } public: // For int. Add to end of array void AddToEnd(int &aArray[],int aValue) { int m_size=ArraySize(aArray); ArrayResize(aArray,m_size+1); aArray[m_size]=aValue; } // For long. Add to end of array void AddToEnd(long &aArray[],long aValue) { int m_size=ArraySize(aArray); ArrayResize(aArray,m_size+1); aArray[m_size]=aValue; } // For int. Add to end of array if there is no such value in array already void AddToEndIfNotExistss(int &aArray[],int aValue) { if(Find(aArray,aValue)==-1) { AddToEnd(aArray,aValue); } } // For long. Add to end of array if there is no such value in array already void AddToEndIfNotExistss(long &aArray[],long aValue) { if(Find(aArray,aValue)==-1) { AddToEnd(aArray,aValue); } } };이제 같은 이름을 사용하면 다른 기능이 있습니다. 하나의 이름이 둘 이상의 기능, 즉 오버로드로 로드되므로 이러한 함수를 오버로드라고 합니다.
이 글 에 첨부된 OOP_CLibArray_1.mqh 파일에서 이 예제를 찾을 수 있습니다.
또 다른 클래스 표기법
위의 예에서 모든 함수는 클래스 내부에 작성되었습니다. 많은 기능이 있고 각각의 기능이 상당히 방대하다면 그러한 표기법이 그다지 편하지 않을 수 있습니다. 이러한 경우 클래스 외부에 함수를 배치할 수 있습니다. 클래스 내부에는 매개 변수가 있는 함수의 이름만 작성하고 함수는 클래스 외부에서 완전히 설명됩니다. 게다가 함수가 특정 클래스에 속함을 나타내야 합니다. 먼저 클래스 이름을 작성한 다음 두 개의 콜론과 함수 이름을 입력합니다.
class CLibArray { private: int Find(int &aArray[],int aValue); int Find(long &aArray[],long aValue); public: void AddToEnd(int &aArray[],int aValue); void AddToEnd(long &aArray[],long aValue); void AddToEndIfNotExistss(int &aArray[],int aValue); void AddToEndIfNotExistss(long &aArray[],long aValue); }; //--- int CLibArray::Find(int &aArray[],int aValue) { for(int i=0; i<ArraySize(aArray); i++) { if(aArray[i]==aValue) { return(i); } } return(-1); } //--- int CLibArray::Find(long &aArray[],long aValue) { for(int i=0; i<ArraySize(aArray); i++) { if(aArray[i]==aValue) { return(i); } } return(-1); } //--- void CLibArray::AddToEnd(int &aArray[],int aValue) { int m_size=ArraySize(aArray); ArrayResize(aArray,m_size+1); aArray[m_size]=aValue; } //--- void CLibArray::AddToEnd(long &aArray[],long aValue) { int m_size=ArraySize(aArray); ArrayResize(aArray,m_size+1); aArray[m_size]=aValue; } //--- void CLibArray::AddToEndIfNotExistss(int &aArray[],int aValue) { if(Find(aArray,aValue)==-1) { AddToEnd(aArray,aValue); } } //--- void CLibArray::AddToEndIfNotExistss(long &aArray[],long aValue) { if(Find(aArray,aValue)==-1) { AddToEnd(aArray,aValue); } }
이러한 표기법을 사용하면 클래스 구성의 전체 그림을 얻고 필요한 경우 개별 함수를 자세히 살펴볼 수 있습니다.
이 글 에 첨부된 OOP_CLibArray_2.mqh 파일에서 이 예제를 찾을 수 있습니다.
클래스에서 변수 선언
앞서 언급한 예를 계속 살펴 보겠습니다. 파일에서 직접 코딩하는 것과 클래스 내부에서 코딩하는 것에는 한 가지 차이점이 있습니다. 파일에서 직접 선언할 때 값으로 변수를 할당할 수 있습니다.
int Var = 123;
클래스에서 변수를 선언하면 이 작업을 수행할 수 없습니다. 클래스의 일부 기능을 실행할 때 값을 할당해야 합니다. 따라서 먼저 매개 변수를 클래스에 전달해야 합니다 (즉, 작업할 클래스 준비). 이 함수의 이름을 Init()로 지정합니다.
실용적인 예를 들어보십시오.
스크립트를 클래스로 변환하는 예
보류중인 주문을 삭제하는 스크립트가 있다고 가정합니다 (첨부된 OOP_sDeleteOrders_1.mq5 파일 참조).
// Include file to use the CTrade class from standard delivery #include <Trade/Trade.mqh> // External parameters // Select symbol. true - delete orders for all symbols, // false - only for symbol of chart, where the script is running input bool AllSymbol=false; // Select types of orders to delete input bool BuyStop = false; input bool SellStop = false; input bool BuyLimit = false; input bool SellLimit = false; input bool BuyStopLimit = false; input bool SellStopLimit = false; // Load the CTrade class CTrade Trade; //--- void OnStart() { // Variable to check function result bool Ret=true; // Loop by all orders in terminal for(int i=0; i<OrdersTotal(); i++) { ulong Ticket=OrderGetTicket(i); // Select order and get its ticket // Successfully selected if(Ticket>0) { long Type=OrderGetInteger(ORDER_TYPE); // Check order type if(Type == ORDER_TYPE_BUY_STOP && !BuyStop) continue; if(Type == ORDER_TYPE_SELL_STOP && !SellStop) continue; if(Type == ORDER_TYPE_BUY_LIMIT && !BuyLimit) continue; if(Type == ORDER_TYPE_SELL_LIMIT && !SellLimit) continue; if(Type == ORDER_TYPE_BUY_STOP_LIMIT && !BuyStopLimit) continue; if(Type == ORDER_TYPE_SELL_STOP_LIMIT && !SellStopLimit) continue; // Check symbol if(!AllSymbol && Symbol()!=OrderGetString(ORDER_SYMBOL)) continue; // Delete if(!Trade.OrderDelete(Ticket)) { Ret=false; // Failed to delete } } // Failed to select order, unknown result, // function ended up with error else { Ret=false; Print("Error selecting order"); } } if(Ret) { Alert("Script ended successfully"); } else { Alert("Script ended up with error, see details. in Journal"); } }
스크립트에는 다양한 유형의 주문을 활성화하고 주문을 삭제할 기호 (스크립트가 실행중인 차트의 모든 기호 또는 기호)를 선택할 수있는 외부 매개 변수가 있습니다.
이 스크립트를 COrderDelete라는 클래스로 변환하십시오. private 섹션에서 스크립트에 선언된 것과 동일한 변수를 외부 매개 변수로 선언하고 변수 이름에 "m _"(단어 "멤버", 즉 클래스의 멤버) 접두사를 선언합니다. 접두사 추가는 필수는 아니지만 변수를 쉽게 구분할 수 있어 매우 편리합니다. 따라서 저희는 클래스 공간에 의해 제한된 변수를 다루고 있음을 확실히 알 수 있습니다. 또한 변수 선언이 전역 범위에서 선언된 변수를 숨긴다는 컴파일러 경고를 받지 않습니다.
전역 범위, 클래스 정의, 함수 본문에서 동일한 변수 이름을 사용하는 것은 오류가 아니지만 프로그램을 이해하기 어렵게 만들기 때문에 이러한 경우 컴파일러에서 경고를 표시합니다. 값이 있는 변수를 할당하려면 이러한 변수 (및 스크립트의 외부 매개 변수)에 해당하는 매개 변수를 사용하여 Init() 함수를 작성하십시오. 이 클래스를 사용하는 경우 먼저 Init() 함수를 호출하고 외부 매개 변수를 전달해야 합니다. 나머지 스크립트 코드는 변경되지 않습니다. 유일한 예외 - 외부 매개 변수를 직접 사용하는 대신 클래스 내에서 선언 된 변수를 사용해야 합니다.
따라서 다음과 같은 클래스를 얻습니다.
#include <Trade/Trade.mqh> class COrderDelete { private: // Variables for parameters bool m_AllSymbol; bool m_BuyStop; bool m_SellStop; bool m_BuyLimit; bool m_SellLimit; bool m_BuyStopLimit; bool m_SellStopLimit; // Load the CTrade class CTrade m_Trade; public: // Function to set parameters void Init(bool aAllSymbol,bool aBuyStop,bool aSellStop,bool aBuyLimit,bool aSellLimit,bool aBuyStopLimit,bool aSellStopLimit) { // Set parameters m_AllSymbol =aAllSymbol; m_BuyStop =aBuyStop; m_SellStop =aSellStop; m_BuyLimit =aBuyLimit; m_SellLimit =aSellLimit; m_BuyStopLimit =aBuyStopLimit; m_SellStopLimit=aSellStopLimit; } Main function to delete orders bool Delete() { // Variable to check function result bool m_Ret=true; // Loop by all orders in terminal for(int i=0; i<OrdersTotal(); i++) { // Select order and get its ticket ulong m_Ticket=OrderGetTicket(i); // Successfully selected if(m_Ticket>0) { long m_Type=OrderGetInteger(ORDER_TYPE); // Check order type if(m_Type == ORDER_TYPE_BUY_STOP && !m_BuyStop) continue; if(m_Type == ORDER_TYPE_SELL_STOP && !m_SellStop) continue; if(m_Type == ORDER_TYPE_BUY_LIMIT && !m_BuyLimit) continue; if(m_Type == ORDER_TYPE_SELL_LIMIT && !m_SellLimit) continue; if(m_Type == ORDER_TYPE_BUY_STOP_LIMIT && !m_BuyStopLimit) continue; if(m_Type == ORDER_TYPE_SELL_STOP_LIMIT && !m_SellStopLimit) continue; // Check symbol/s61> if(!m_AllSymbol && Symbol()!=OrderGetString(ORDER_SYMBOL)) continue; // Delete if(!m_Trade.OrderDelete(m_Ticket)) { m_Ret=false; // Failed to delete } } // Failed to select order, unknown result, // function ended up with error else { m_Ret=false; Print("Error selecting order"); } } // Return function result return(m_Ret); } };이 문서에 첨부된 OOP_CDeleteOrder_1.mqh 파일에서 이 클래스의 예를 찾을 수 있습니다. 이 클래스를 사용하는 스크립트는 최소한으로 축소됩니다 (외부 매개 변수, 클래스로드, Init() 및 Delete() 메소드 호출).
// External parameters // Select symbol. true - delete orders for all symbols, // false - only for symbol of chart, where the script is running input bool AllSymbol=false; // Select types of orders to delete input bool BuyStop = false; input bool SellStop = false; input bool BuyLimit = false; input bool SellLimit = false; input bool BuyStopLimit = false; input bool SellStopLimit = false; // Include file with class #include <OOP_CDeleteOrder_1.mqh> // Load class COrderDelete od; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnStart() { // Pass external parameters to the class od.Init(AllSymbol,BuyStop,SellStop,BuyLimit,SellLimit,BuyStopLimit,SellStopLimit); // Delete orders bool Ret=od.Delete(); // Process result of deleting if(Ret) { Alert("Script ended successfully"); } else { Alert("Script ended up with error, see details in Journal"); } }
이 문서에 첨부된 OOP_sDeleteOrders_2.mq5 파일에서 이 스크립트의 예를 찾을 수 있습니다. 대부분의 스크립트는 Delete() 함수의 결과를 처리하므로 스크립트 결과를 알립니다.
이제 스크립트의 모든 기본 기능이 별도의 파일에있는 클래스로 설계되었으므로 다른 프로그램 (Expert Advisor 또는 Script)에서이 클래스를 사용할 수 있습니다. 즉, Expert Advisor에서 이 스크립트를 호출할 수 있습니다.
약간의 자동화 (생성자 및 소멸자)
프로그램 운영은 프로그램 실행, 작업 프로세스, 작업 완료의 세 단계로 나눌 수 있습니다. 이 분리의 중요성은 분명합니다. 프로그램이 시작될 때 자체 준비 (예 : 작업 할 매개 변수로드 및 설정), 프로그램 종료시 "정리"해야 합니다 (예 : 차트에서 그래픽 개체 제거).
이러한 단계를 분리하기 위해 Expert Advisors 및 인디케이터에는 OnInit() (시작시 실행) 및 OnDeinit() (종료시 실행)과 같은 특수 기능이 있습니다. 클래스에는 비슷한 기능이 있습니다. 클래스가 로드되고 언로드 될 때 자동으로 실행되는 함수를 추가할 수 있습니다. 이러한 함수를 생성자 및 소멸자라고 합니다. 클래스에 생성자를 추가한다는 것은 클래스 이름과 정확히 같은 이름으로 함수를 추가하는 것을 의미합니다. 소멸자를 추가하려면 - 생성자와 동일하게 모든 작업을 수행하지만 함수 이름은 물결표 "~"로 시작합니다.
생성자와 소멸자를 보여주는 스크립트:
// Class class CName { public: // Constructor CName() { Alert("Constructor"); } // Destructor ~CName() { Alert("Destructor"); } void Sleep() { Sleep(3000); } }; // Load class CName cname; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnStart() { // Pause cname.Sleep(); }
이 클래스에는 실제로 3 초 동안 일시 중지하는 Sleep() 함수가 하나만 있습니다. 스크립트를 실행하면 "Constructor"메시지가 있는 경고 창이 나타나고 3 초 동안 일시 중지 된 후 "소멸자" 메시지가 있는 경고 창이 표시됩니다. 이것은 CName() 및 ~ CName() 함수가 명시 적으로 호출되지 않았음에도 불구하고 그렇습니다.
이 예는 이 글 에 첨부 된 OOP_sConstDestr_1.mq5 파일에서 찾을 수 있습니다.
생성자에게 매개 변수 전달
스크립트를 클래스로 변환한 예제에서 코드의 양을 한 줄 줄일 수 있습니다. Init() 함수를 호출하지 않아도 됩니다. 클래스를 로드할 때 매개 변수를 생성자에 전달할 수 있습니다. 클래스에 생성자를 추가합니다.
COrderDelete(bool aAllSymbol = false, bool aBuyStop = false, bool aSellStop = false, bool aBuyLimit = false, bool aSellLimit = false, bool aBuyStopLimit = false, bool aSellStopLimit=false) { Init(aAllSymbol,aBuyStop,aSellStop,aBuyLimit,aSellLimit,aBuyStopLimit,aSellStopLimit); }
Init() 함수는 그대로 유지되지만 생성자에서 호출됩니다. 생성자의 모든 매개 변수는 선택 사항이므로 이전과 같이 클래스를 사용할 수 있습니다. 매개 변수없이 클래스를 로드하고 Init() 함수를 호출합니다.
생성자를 만든 후 이 클래스를 사용하는 다른 방법이 있습니다. Init() 함수를 호출할 필요없이 변수를 많은 수 있습니다.
COrderDelete od(AllSymbol,BuyStop,SellStop,BuyLimit,SellLimit,BuyStopLimit,SellStopLimit);
Init() 함수는 클래스 재 초기화를 허용하기 위해 public 섹션에 남아 있습니다. 프로그램 (Expert Advisor)을 사용할 때 한 경우에는 Stop 주문만 제거해야 할 수도 있고 다른 경우에는 Limit 문 만 제거해야 할 수도 있습니다. 이렇게 하려면 다른 매개 변수를 사용하여 Init() 함수를 호출하여 Delete() 함수가 다른 주문 세트를 삭제하도록 할 수 있습니다.
이 문서에 첨부된 OOP_CDeleteOrder_2.mqh 및 OOP_sDeleteOrders_3.mq5 파일에서 이 예제를 찾을 수 있습니다.
클래스의 여러 인스턴스 사용
이전 섹션에서 언급했듯이 동일한 클래스는 초기화 중에 설정되는 매개 변수에 따라 다른 작업을 수행 할 수 있습니다. 클래스가 어떤 용도로 사용되는지 알고 있다면 클래스 재초기화를 생략 할 수 있습니다. 이렇게 하려면 다른 매개 변수를 사용하여 몇 개의 클래스 인스턴스를 로드해야 합니다.
예를 들어, EA가 실행 중일 때 어떤 경우에는 BuyStop 및 BuyLimit 주문을 삭제해야 하는 반면 다른 경우에는 SellStop 및 SellLimit 주문을 삭제해야 합니다. 이 경우 클래스의 두 인스턴스를 로드할 수 있습니다.
BuyStop 및 BuyLimit 주문을 삭제하려면:
COrderDelete DeleteBuy(false,true,false,true,false,false,false);
SellStop 및 SellLimit 주문을 삭제하려면:
COrderDelete DeleteSell(false,false,true,false,true,false,false);
이제 구매 보류 주문을 삭제하려면 클래스의 한 인스턴스를 사용하십시오.
DeleteBuy.Delete();
판매 보류 주문을 삭제하려는 경우 - 다른 인스턴스:
DeleteSell.Delete();
객체 배열
프로그램이 실행 중일 때 필요한 클래스 인스턴스 수를 항상 알 수는 없습니다. 이 경우 클래스 인스턴스 (객체)의 배열을 만들 수 있습니다. 생성자와 소멸자가 있는 클래스의 예를 살펴 보겠습니다. 클래스를 약간 변경하여 생성자에 매개 변수를 전달하여 클래스의 각 인스턴스를 모니터링 할 수 있습니다.
// Class class CName { private: int m_arg; // Variable for the instance public: // Constructor CName(int aArg) { m_arg=aArg; Alert("Constructor "+IntegerToString(m_arg)); } // Destructor ~CName() { Alert("Destructor "+IntegerToString(m_arg)); } //--- void Sleep() { Sleep(3000); } };이 클래스를 사용합시다. 특정 크기의 배열 (예 : 10 개 요소)을 선언할 수 있습니다.
CName* cname[10];
일반적인 변수 선언과의 차이점은 별표 "*" 입니다. 별표는 이전에 사용된 자동 포인터와 달리 동적 포인터가 사용되었음을 나타냅니다.
동적 배열을 사용할 수 있습니다 (사전 할당된 크기없이 동적 배열과 동적 포인터를 혼동하지 마십시오).
CName* cname[];
이 경우 확장이 필요합니다 (모든 함수, 스크립트에서 OnStart() 함수 내부에서 수행됨).
ArrayResize(cname,10);
이제 배열의 모든 요소를 반복하고 각 요소에 클래스 인스턴스를 로드합니다. 이렇게하려면 new 키워드를 사용하십시오.
ArrayResize(cname,10); for(int i=0; i<10; i++) { cname[i]=new CName(i); }중지:
cname[0].Sleep();
스크립트를 확인하십시오. 그것을 실행하고 10 개의 생성자가 있지만 소멸자가 없는지 확인하십시오. 동적 포인터를 사용하면 프로그램이 종료될 때 클래스가 자동으로 언로드되지 않습니다. 또한 "Experts"탭에서 메모리 누수에 대한 메시지를 볼 수 있습니다. 개체를 수동으로 삭제해야 합니다.
for(int i=0; i<10; i++) { delete(cname[i]); }
이제 스크립트 끝에 10 개의 소멸자가 실행 중이고 오류 메시지가 없습니다.
이 문서에 첨부된 OOP_sConstDestr_2.mq5 파일에서 이 예제를 찾을 수 있습니다.
OOP를 사용하여 프로그램 논리 변경 (가상 함수, 다형성)
다형성 - 아마도 이것은 프로그램의 논리를 제어 할 수있는 가장 흥미롭고 중요한 OOP 기능입니다. 가상 함수와 여러 하위 클래스가 있는 기본 클래스를 사용합니다. 한 클래스는 차일드 클래스에서 정의한 여러 형식을 취할 수 있습니다.
간단한 예를 들어 두 값을 비교합니다. 보다 큼 (>),보다 작음 (<),보다 크거나 같음 (>=), 작거나 같음 (<=), 같음 (==)의 다섯 가지 버전의 비교가 있을 수 있습니다.
가상 기능이 있는 기본 클래스를 만듭니다. 가상 함수 - 정확히 동일한 일반 함수이지만 선언은 virtual이라는 단어로 시작합니다.
class CCheckVariant { public: virtual bool CheckVariant(int Var1,int Var2) { return(false); } };
가상 기능에는 코드가 없습니다. 다양한 장치를 수용하는 일종의 커넥터입니다. 장치 유형에 따라 다른 작업을 수행합니다.
5 개의 하위 클래스를 만듭니다.
//+------------------------------------------------------------------+ //| > | //+------------------------------------------------------------------+ class CVariant1: public CCheckVariant { bool CheckVariant(int Var1,int Var2) { return(Var1>Var2); } }; //+------------------------------------------------------------------+ //| < | //+------------------------------------------------------------------+ class CVariant2: public CCheckVariant { bool CheckVariant(int Var1,int Var2) { return(Var1<Var2); } }; //+------------------------------------------------------------------+ //| >= | //+------------------------------------------------------------------+ class CVariant3: public CCheckVariant { bool CheckVariant(int Var1,int Var2) { return(Var1>=Var2); } }; //+------------------------------------------------------------------+ //| <= | //+------------------------------------------------------------------+ class CVariant4: public CCheckVariant { bool CheckVariant(int Var1,int Var2) { return(Var1<=Var2); } }; //+------------------------------------------------------------------+ //| == | //+------------------------------------------------------------------+ class CVariant5: public CCheckVariant { bool CheckVariant(int Var1,int Var2) { return(Var1==Var2); } };
이 클래스를 사용하기 전에 로드해야 합니다. 어떤 차일드 클래스를 사용해야하는지 알고 있다면 이 차일드의 유형으로 포인터를 선언 할 수 있습니다. 예를 들어 ">"조건을 확인하려면:
CVariant1 var; // Load class to check the ">" condition
저희의 경우와 같이 차일드 유형을 미리 알지 못하면 클래스에 대한 포인터가 기본 클래스 유형으로 선언됩니다. 그러나 이 경우 동적 포인터가 사용됩니다.
CCheckVariant* var;
이 하위 항목은 new 키워드를 사용하여 로드되어야 합니다. 선택한 변형에 따라 하위로드:
// Number of variant int Variant=5; // Depending on variant number one of five children classes will be used switch(Variant) { case 1: var = new CVariant1; break; case 2: var = new CVariant2; break; case 3: var = new CVariant3; break; case 4: var = new CVariant4; break; case 5: var = new CVariant5; break; }
조건 확인:
bool rv = var.CheckVariant(1,2);
조건을 확인하는 코드가 모든 경우에 동일하더라도 두 값을 비교한 결과는 차일드 클래스에 따라 다릅니다.
이 글 에 첨부된 OOP_sVariant_1.mq5 파일에서 이 예제를 찾을 수 있습니다.
캡슐화에 대한 추가 정보 (개인, 보호, 공개)
현재로서는 public 섹션을 통해 매우 명확합니다. in에는 클래스 사용자가 볼 수 있어야 하는 함수와 변수가 포함되어 있습니다. 클래스 사용자 관점에서는 protected 섹션과 private 섹션간에 차이가 없습니다. 이 섹션의 함수와 변수는 사용자가 사용할 수 없습니다.
//+------------------------------------------------------------------+ //| Class with the protected keyword | //+------------------------------------------------------------------+ class CName1 { protected: int ProtectedFunc(int aArg) { return(aArg); } public: int PublicFunction(int aArg) { return(ProtectedFunc(aArg)); } }; //+------------------------------------------------------------------+ //| Class with the private keyword | //+------------------------------------------------------------------+ class CName2 { private: int PrivateFunc(int aArg) { return(aArg); } public: int PublicFunction(int aArg) { return(PrivateFunc(aArg)); } }; CName1 c1; // Load class with the protected keyword CName2 c2; // Load class with the private keyword이 예에는 CName1과 CName2의 두 가지 클래스가 있습니다. 각 클래스에는 두 가지 기능이 있습니다. 하나는 public 섹션에 있고 다른 하나는 protected 섹션 (클래스 CName1의 경우) 또는 private에 있습니다. 섹션 (클래스 CName2 용). 두 클래스 모두 함수 드롭 다운 목록의 public 섹션에 있는 함수 하나만 있습니다 (그림 2 및 3).
그림 2. CName1 클래스의 기능
그림 3. CName2 클래스의 기능
이 예제는 이 글 에 첨부 된 OOP_sProtPriv_1.mq5 파일에서 찾을 수 있습니다.
private 및 protected 섹션은 하위 클래스에 대한 기본 클래스 함수의 가시성을 결정합니다.
//+------------------------------------------------------------------+ //| Base class | //+------------------------------------------------------------------+ class CBase { protected: string ProtectedFunc() { return("CBase ProtectedFunc"); } private: string PrivateFunc() { return("CBase PrivateFunc"); } public: virtual string PublicFunction() { return(""); } }; //+------------------------------------------------------------------+ //| Child class | //+------------------------------------------------------------------+ class Class: public CBase { public: string PublicFunction() { // With this line everything compiles correctly return(ProtectedFunc()); // If you will uncomment this line and comment the previous one, there will be a compiler error // return(PrivateFunc()); } };
이 예제에서는 CBase라는 기본 클래스와 Class라는 차일드 클래스가 있습니다. 하위 클래스의 protected 및 private 섹션에 있는 기본 클래스 함수를 호출 해보세요. protected 섹션에서 함수를 호출하면 모든 것이 컴파일되고 실행됩니다. private 섹션에서 함수를 호출하면 컴파일러 오류가 표시됩니다 (개인 멤버 함수를 호출 할 수 없음). 즉, private 섹션의 기능은 하위 클래스에 표시되지 않습니다.
protected 섹션은 클래스 사용자의 함수 만 보호하고 private 섹션은 하위 클래스의 함수도 보호합니다. 차일드 클래스의 기본 클래스 함수 (다른 섹션에 있음)의 가시성은 그림 4에 나와 있습니다.
그림 4. 차일드 클래스의 기본 클래스 함수 가시성
파란색 화살표 - 기능 사용 가능, 회색 - 사용 불가능
이 문서에 첨부 된 OOP_sProtPriv_2.mq5 파일에서 이 예제를 찾을 수 있습니다.
기본 가상 기능 및 상속
기본 클래스의 모든 가상 함수가 차일드 클래스의 해당 함수를 가져야 하는 것은 아닙니다. 차일드 클래스가 같은 이름의 함수를 가지고 있다면 - 바로 이 함수를 사용할 것이고, 그렇지 않다면 기본 클래스 가상 함수에서 코드를 실행할 것입니다. 예를 들어 고려하십시오.
//+------------------------------------------------------------------+ //| Base Class | //+------------------------------------------------------------------+ class CBase { public: virtual string Function() { string str=""; str="Function "; str=str+"of base "; str=str+"class"; return(str); } }; //+------------------------------------------------------------------+ //| Child class 1 | //+------------------------------------------------------------------+ class Class1: public CBase { public: string Function() { string str=""; str="Function "; str=str+"of child "; return(str); } }; //+------------------------------------------------------------------+ //| Child class 2 | //+------------------------------------------------------------------+ class Class2: public CBase { }; Class1 c1; // Load class 1 Class2 c2; // Load class 2 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnStart() { Alert("1: "+c1.Function()); // Running function from Class1 Alert("2: "+c2.Function()); // Running function from CBase }
Class2 클래스에 함수가 없다는 사실에도 불구하고 이 클래스에서 Function() 함수를 호출 할 수 있습니다. 이것은 CBase 클래스에서 함수를 실행합니다. Class1 클래스는 자체 기능을 실행합니다.
void OnStart() { Alert("1: " + c1.Function()); // Running function from Class1 Alert("2: " + c2.Function()); // Running function from CBase }
클래스 사용자 관점에서 차일드 클래스를 사용할 때 public 섹션의 기본 클래스의 모든 기능을 사용할 수 있습니다. 이것을 상속이라고 합니다. 기본 클래스의 함수가 virtual로 선언 된 경우 차일드 클래스에 이 이름의 함수가 있으면 차일드 클래스의 함수로 대체됩니다 (그림 5).
그림 5. 클래스 사용자가 함수에 액세스
차일드 클래스에 기본 클래스의 가상 함수에 해당하는 함수가없는 경우를 제외하고 차일드 클래스는 "추가" 함수 (기본 클래스 내에 동일한 이름의 가상 함수가 없는 함수)를 가질 수 있습니다. 차일드 클래스 유형에 대한 포인터를 사용하여 클래스를 로드하면 이러한 함수를 사용할 수 있습니다. 기본 클래스 유형에 대한 포인터를 사용하여 클래스를 로드하면 이러한 함수를 사용할 수 없습니다 (그림 6).
그림 6. "추가"기능 (빨간색 화살표)의 가시성이 결정됩니다.
클래스를 로드하는 데 사용되는 포인터 유형별.
이 문서에 첨부 된 OOP_sDefaultVirtual_1.mq5 파일에서 이 예제를 찾을 수 있습니다.
클래스 로딩에 대한 추가 정보
가상 함수를 사용할 때 기본 클래스와 차일드 클래스를 사용할 때 어떤 차일드 클래스를 사용해야 하는지 알고 있다면 차일드 클래스에 해당하는 포인터를 사용할 수 있습니다.
Class1 c1; // Load class 1 Class2 c2; // Load class 2
어떤 차일드 클래스를 사용해야하는지 알 수없는 경우 기본 클래스 유형에 대한 동적 포인터를 사용하고 new 키워드를 사용하여 클래스를 로드합니다.
CBase *c; // Dynamic pointer void OnStart() { c=new Class1; // Load class ...
기본 클래스에 대한 자동 포인터를 사용하는 경우
CBase c; // Automatic pointer
기본 클래스는 그대로 사용됩니다. 가상 함수를 호출하면 이러한 함수 내에 있는 코드가 실행됩니다. 가상 기능은 일반 기능으로 변환됩니다.
함수에서 개체 처리
이 섹션의 제목은 자급 자족합니다. 객체에 대한 포인터는 함수에 전달될 수 있으며 함수 내에서 객체 함수를 호출 할 수 있습니다. 함수 매개 변수는 기본 클래스 유형으로 선언 할 수 있습니다. 이것은 기능을 보편적으로 만듭니다. 클래스에 대한 포인터는 참조 (& 표시로 표시)에 의해서만 함수에 전달 될 수 있습니다.
//+------------------------------------------------------------------+ //| Base Class | //+------------------------------------------------------------------+ class CBase { public: virtual string Function() { return(""); } }; //+------------------------------------------------------------------+ //| Child class 1 | //+------------------------------------------------------------------+ class Class1: public CBase { public: string Function() { return("Class 1"); } }; //+------------------------------------------------------------------+ //| Child class 2 | //+------------------------------------------------------------------+ class Class2: public CBase { public: string Function() { return("Class 2"); } }; Class1 c1; // Load class 1 Class2 c2; // Load class 2 //+------------------------------------------------------------------+ //| Function to process objects | //+------------------------------------------------------------------+ void Function(CBase &c) { Alert(c.Function()); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnStart() { // Process objects using one function. Function(c1); Function(c2); }이 문서에 첨부 된 OOP_sFunc_1.mq5 파일에서 이 예제를 찾을 수 있습니다.
함수 및 방법, 변수 및 속성
지금까지 이 글에서는 "기능"이라는 단어를 사용했습니다. 그러나 OOP에서 "기능"이라는 단어 대신 프로그래머는 종종 "방법"이라는 단어를 사용합니다. 클래스를 작성하는 프로그래머의 관점에서 내부에서 클래스를 보면 모든 함수가 함수로 남아 있습니다. 미리 만들어진 클래스를 사용하는 프로그래머의 관점에서 클래스를 보면 public 섹션 (점을 입력 한 후 드롭 다운 목록에서 사용 가능)에 있는 클래스 인터페이스는 메소드라고 불립니다.
메소드 클래스 인터페이스 외에 클래스 속성을 포함할 수 있습니다. public 섹션은 함수뿐만 아니라 변수 (배열 포함)도 포함 할 수 있습니다.
class CMethodsAndProperties { public: int Property1; // Property 1 int Property2; // Property 2 void Function1() { //... return; } void Function2() { //... return; } };
이러한 변수를 클래스 속성이라고 하며 드롭 다운 목록에서도 사용할 수 있습니다 (그림 7).
그림 7. 하나의 목록에있는 클래스의 메소드 및 속성
이러한 속성은 변수와 동일한 방식으로 사용할 수 있습니다.
void OnStart() { c.Property1 = 1; // Set property 1 c.Property2 = 2; // Set property 2 // Read properties Alert("Property1 = " + IntegerToString(c.Property1) + ", Property2 = " + IntegerToString(c.Property2)); }
이 문서에 첨부된 OOP_sMethodsAndProperties.mq5 파일에서 이 예제를 찾을 수 있습니다.
데이터 구조
데이터 구조는 클래스와 비슷하지만 조금 더 쉽습니다. 그렇게 말할 수는 있지만 : 클래스는 데이터 구조와 비슷하지만 오히려 더 복잡합니다. 차이점은 데이터 구조가 변수만 포함할 수 있다는 것입니다. 이와 관련하여 공개, 비공개 및 보호 섹션으로 나눌 필요가 없습니다. 구조의 모든 내용은 이미 public 섹션에 있습니다. 데이터 구조는 struct 단어로 시작하고 그 뒤에 구조 이름이 오고 중괄호 안에 변수를 선언합니다.
struct Str1 { int IntVar; int IntArr[]; double DblVar[]; double DblArr[]; };
구조를 사용하려면 변수로 선언해야 하지만 변수 유형 대신 구조 이름을 사용합니다.
Str1 s1;
구조 배열을 선언할 수도 있습니다.
Str1 sar1[];
구조는 변수와 배열뿐만 아니라 다른 구조도 포함 할 수 있습니다.
struct Str2 { int IntVar; int IntArr[]; double DblVar[]; double DblArr[]; Str1 Str; };
이 경우 구조 2의 일부인 구조 1에서 변수를 호출하려면 두 점을 사용해야 합니다.
s2.Str.IntVar=1;
이 글 에 첨부 된 OOP_Struct.mq5 파일에서 이 예제를 찾을 수 있습니다.
클래스에는 변수 뿐만 아니라 구조도 포함될 수 있습니다.
결론
객체 지향 프로그래밍의 요점과 기억해야 할 중요한 순간을 검토해 보겠습니다.
1. 클래스는 class 키워드와 클래스 이름을 사용하여 생성되고 중괄호 안에는 세 섹션으로 작성된 클래스 코드가 있습니다.
class CName { private: protected: public: };
2. 클래스의 함수와 변수는 private, protected 및 public의 세 섹션 중 하나에 있을 수 있습니다. private 섹션의 함수와 변수는 클래스 내에서만 사용할 수 있습니다. 클래스 및 하위 클래스에서 사용할 수있는 protected 섹션의 함수 및 변수입니다. public 섹션의 함수와 변수는 모두 사용할 수 있습니다.
3. 클래스 함수는 클래스 내부 또는 외부에 있을 수 있습니다. 클래스 외부에 함수를 배치하는 경우 각 함수 이름 앞에 클래스 이름과 두 개의 콜론을 배치하여 해당 함수가 속한 클래스를 식별해야 합니다.
void ClassName::FunctionName() { ... }
4. 자동 및 동적 포인터를 사용하여 클래스를 로드 할 수 있습니다. 동적 포인터 클래스를 사용할 때는 new 키워드를 사용하여 로드해야 합니다. 이 경우 프로그램을 종료할 때 delete 키워드를 사용하여 개체를 삭제해야 합니다.
5. 하위 클래스가 기본 클래스에 속함을 알리려면 하위 클래스 이름 뒤에 기본 클래스 이름을 추가해야 합니다.
class Class : public CBase { ... }
6. 클래스 초기화 중에는 값으로 변수를 할당 할 수 없습니다. 일부 함수, 더 자주 생성자를 실행하는 동안 값을 할당 할 수 있습니다.
7. 가상 함수는 virtual 키워드를 사용하여 선언됩니다. 차일드 클래스에 같은 이름의 함수가 있으면 바로 이 함수를 실행하고, 그렇지 않으면 기본 클래스의 가상 함수를 실행합니다.
8. 클래스에 대한 포인터를 함수에 전달할 수 있습니다. 기본 클래스 유형으로 함수 매개 변수를 선언 할 수 있으므로 모든 차일드 클래스에 대한 포인터를 함수에 전달할 수 있습니다.
9. public 섹션에는 함수 (메소드) 뿐만 아니라 변수 (속성)도 있습니다.
10. 구조에는 배열 및 기타 구조가 포함될 수 있습니다.
첨부 파일 목록
- OOP_CLibArray_1.mqh - 포함된 파일은 MQL5/Include 폴더에 있어야 합니다. 클래스를 사용하여 라이브러리를 만드는 예. 보호된 및 비공개 키워드. 초과 적재
- OOP_CLibArray_2.mqh - 포함된 파일, MQL5/Include 폴더에 위치해야 합니다. 클래스를 넘어서 클래스 함수를 배치하는 예.
- OOP_sDeleteOrders_1.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 보류중인 주문을 삭제하는 간단한 스크립트입니다.
- OOP_CDeleteOrder_1.mqh - 포함된 파일은 MQL5/Include 폴더에 있어야 합니다. OOP_sDeleteOrders_1 스크립트를 클래스로 변환하는 예.
- OOP_sDeleteOrders_2.mq5 - 포함된 파일은 MQL5/Include 폴더에 있어야 합니다. 클래스를 사용하여 주문을 삭제하는 예. OOP_CDeleteOrder_1.mqh 파일에서 가져옵니다 (Init() 함수를 통해 매개 변수 설정).
- OOP_sConstDestr_1.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 생성자 및 소멸자 데모.
- OOP_CDeleteOrder_2.mqh - 포함된 파일, MQL5/Include 폴더에 위치해야 합니다. 생성자로 주문을 삭제하고 생성자를 통해 매개 변수를 전달하는 클래스입니다.
- OOP_sDeleteOrders_3.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 클래스를 사용하여 주문을 삭제하는 예. OOP_CDeleteOrder_2.mqh 파일에서 가져옵니다 (생성자를 통해 매개 변수 설정).
- OOP_sConstDestr_2.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 클래스를 배열로 로드하는 예.
- OOP_sVariant_1.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 차일드이 있는 기본 클래스의 예. 가상 기능, 다형성.
- OOP_sProtPriv_1.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 클래스를 사용할 때 protected 및 private 키워드의 ID 예입니다.
- OOP_sProtPriv_2.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 하위 클래스의 protected 및 private 키워드에 영향을 미치는 예.
- OOP_sDefaultVirtual_1.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 기본 클래스의 가상 기능에 해당하는 기능이없는 차일드 클래스의 예.
- OOP_sFunc_1.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 함수에서 객체를 사용하는 예.
- OOP_sMethodsAndProperties.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 속성의 예.
- OOP_Struct.mq5 - 스크립트는 MQL5/Scripts 폴더에 있어야 합니다. 구조의 예.
이러한 파일을 실험 한 후 OOP_CDeleteOrder_2.mqh 및 OOP_sDeleteOrders_3.mq5를 제외한 모든 파일을 삭제할 수 있습니다. OOP_CDeleteOrder_2.mqh 및 OOP_sDeleteOrders_3.mq5 파일은 실제 프로그래밍에 유용할 수 있습니다.
MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/351