کلاس در زبان MQL5 – بخش 1


در دو مقاله پیشین یعنی چهارمین و پنجمین مقاله آموزش زبان mql از سری مقالات مرتبط با برنامهنویسی در بازارهای مالی به شرح و بررسی «ساختار در زبان MQL5» پرداختیم. در ششمین مقالهی این سری نیز به «کلاس در زبان MQL5» میپردازیم.
– – –
انواع داده های پیچیده (Complex data types)

در دو مقاله پیشین یعنی سومین و چهارمین مقاله آموزش زبان mql از سری مقالات مرتبط با برنامهنویسی در بازارهای مالی به شرح و بررسی «ساختار در زبان MQL5» پرداختیم. در پنجمین مقالهی این سری نیز به بررسی «کلاس در زبان MQL5» میپردازیم.
کلاسها (Classes) #
در برنامه نویسی شی گرا( Object-oriented programming)، یک کلاس blueprint یا طرحی کلی برای ایجاد اشیا (یک ساختار داده خاص)، ارائه مقادیر اولیه برای state ها یا حالتها (متغیرها یا attribute ها اعضا)، و اجرای رفتار (functionها یا methodهای اعضا) است.
- کلمه کلیدی class در تعریف(declaration) کلاسها به کار برده میشود.
ساختارها و کلاسها در زبان MQL5
کلاسها با ساختارها در موارد زیر متفاوت هستند:
- اعضای داده کلاس دارای نوع دسترسی پیشفرض private هستند(specifier private)، مگر اینکه خلاف آن مشخص شده باشد.
- اعضای داده ساختار دارای نوع دسترسی پیشفرض public هستند(specifier public)، مگر اینکه خلاف آن مشخص شده باشد.
- اشیاء کلاس همیشه جدولی از توابع مجازی(virtual functions) دارند، حتی اگر هیچ تابع مجازی در کلاس وجود نداشته باشد. ساختارها نمیتوانند توابع مجازی داشته باشند.
- عملگر new را میتوان برای اشیاء کلاس اعمال کرد. این عملگر را نمیتوان برای ساختارها اعمال کرد.
- کلاسها را فقط از کلاسها میتوان به ارث برد.
- ساختارها را فقط از ساختارها میتوان به ارث برد.


Constructors and Destructors
سازنده یک تابع ویژه است که به طور خودکار هنگام ایجاد یک شی از یک ساختار یا یک کلاس فراخوانی میشود و معمولاً برای مقداردهی اولیه(initialization) اعضای کلاس استفاده میشود.

علاوه بر این، ما فقط در مورد کلاسها صحبت خواهیم کرد، در حالی که همین امر در مورد ساختارها نیز صدق میکند، مگر اینکه خلاف آن مشخص شده باشد.
Default constructor-Parametric constructor
constructor و initializing sequence
- کلاسها و ساختارها میتوانند سازنده(explicit constructor) و تخریبکننده(explicit destructor) صریح داشته باشند.
- اگر constructor شما به صراحت تعریف شده باشد، مقداردهی اولیه یک ساختار یا متغیر کلاس با استفاده از دنباله مقداردهی اولیه(initializing sequence) غیرممکن است.
struct trade_settings { double take; // values of the profit fixing price double stop; // value of the protective stop price uchar slippage; // value of the acceptable slippage //--- Constructor trade_settings() { take=0.0; stop=0.0; slippage=5; } //--- Destructor ~trade_settings() { Print("This is the end"); } }; //--- Compiler will generate an error message that initialization is impossible trade_settings my_set={0.0,0.0,5};
در این مثال برای رفع اررور یا میبایست explicit constructor حذف گردد و یا initializing sequence.
- توجه به این نکته الزامیست که تفاوتی ندارد که explicit constructor از نوع Default constructor باشد و یا Parametric constructor.
- نام سازنده باید با نام کلاس مطابقت داشته باشد.
- سازنده هیچ نوع مقدار خروجی ندارد. (شما میتوانید نوع void را مشخص کنید).
- اعضای کلاس تعریف شده – رشتهها، آرایههای پویا(dynamic arrays) و اشیایی که نیاز به مقداردهی اولیه دارند – در هر صورت، صرف نظر از اینکه سازنده وجود داشته باشد، مقداردهی اولیه خواهند شد.
- Parametric constructor : هر کلاس میتواند سازندههای متعددی داشته باشد که بر اساس تعداد پارامترها و لیست اولیه متفاوت است. سازندهای که نیاز به تعیین پارامتر دارد، سازنده پارامتری(Parametric constructor) نامیده میشود.
- Default constructor : سازنده بدون پارامتر، سازنده پیشفرض(Default constructor) نامیده میشود. اگر هیچ سازندهای در یک کلاس تعریف نشده باشد، کامپایلر یک Default constructor در طول کامپایل ایجاد میکند.
//+------------------------------------------------------------------+ //| A class for working with a date | //+------------------------------------------------------------------+ class MyDateClass { private: int m_year; // Year int m_month; // Month int m_day; // Day of the month int m_hour; // Hour in a day int m_minute; // Minutes int m_second; // Seconds public: //--- Default constructor MyDateClass(void); //--- Parametric constructor MyDateClass(int h,int m,int s); };
یک سازنده(Constructor) را میتوان در توضیحات کلاس تعریف کرد و سپس بدنه آن را تعریف کرد. به عنوان مثال، دو سازنده MyDateClass را میتوان به صورت زیر تعریف کرد. :
//+------------------------------------------------------------------+ //| Default constructor | //+------------------------------------------------------------------+ MyDateClass::MyDateClass(void) { //--- MqlDateTime mdt; datetime t=TimeCurrent(mdt); m_year=mdt.year; m_month=mdt.mon; m_day=mdt.day; m_hour=mdt.hour; m_minute=mdt.min; m_second=mdt.sec; Print(__FUNCTION__); } //+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ MyDateClass::MyDateClass(int h,int m,int s) { MqlDateTime mdt; datetime t=TimeCurrent(mdt); m_year=mdt.year; m_month=mdt.mon; m_day=mdt.day; m_hour=h; m_minute=m; m_second=s; Print(__FUNCTION__); }
در مثال بالا در Default constructor، تمام اعضای کلاس با استفاده از تابع ()TimeCurrent پر میشوند. در Parametric constructor فقط مقادیر ساعت پر میشود. سایر اعضای کلاس (m_year، m_month و m_day) به طور خودکار با تاریخ فعلی مقداردهی اولیه میشوند.
Default constructor هنگام مقداردهی اولیه آرایهای از اشیاء کلاس خود، هدف خاصی دارد. constructor ای که پارامترهای آن دارای مقادیر پیشفرض هستند، Default constructor نیست.
.Constructor with a parameter that has a default value is not a Default constructor
به عنوان مثال:
//+------------------------------------------------------------------+ //| A class with a default constructor | //+------------------------------------------------------------------+ class CFoo { datetime m_call_time; // Time of the last object call public: //--- Constructor with a parameter that has a default value is not a default constructor CFoo(const datetime t=0){m_call_time=t;}; //--- Copy constructor CFoo(const CFoo &foo){m_call_time=foo.m_call_time;}; string ToString(){return(TimeToString(m_call_time,TIME_DATE|TIME_SECONDS));}; }; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { // CFoo foo; // This variant cannot be used - a default constructor is not set //--- Possible options to create the CFoo object CFoo foo1(TimeCurrent()); // An explicit call of a parametric constructor CFoo foo2(); // An explicit call of a parametric constructor with a default parameter CFoo foo3=D'2009.09.09'; // An implicit call of a parametric constructor CFoo foo40(foo1); // An explicit call of a copy constructor CFoo foo41=foo1; // An implicit call of a copy constructor CFoo foo5; // An explicit call of a default constructor (if there is no default constructor, // then a parametric constructor with a default value is called) //--- Possible options to receive CFoo pointers CFoo *pfoo6=new CFoo(); // Dynamic creation of an object and receiving of a pointer to it CFoo *pfoo7=new CFoo(TimeCurrent());// Another option of dynamic object creation CFoo *pfoo8=GetPointer(foo1); // Now pfoo8 points to object foo1 CFoo *pfoo9=pfoo7; // pfoo9 and pfoo7 point to one and the same object // CFoo foo_array[3]; // This option cannot be used - a default constructor is not specified //--- Show the value of m_call_time Print("foo1.m_call_time=",foo1.ToString()); Print("foo2.m_call_time=",foo2.ToString()); Print("foo3.m_call_time=",foo3.ToString()); Print("foo4.m_call_time=",foo4.ToString()); Print("foo5.m_call_time=",foo5.ToString()); Print("pfoo6.m_call_time=",pfoo6.ToString()); Print("pfoo7.m_call_time=",pfoo7.ToString()); Print("pfoo8.m_call_time=",pfoo8.ToString()); Print("pfoo9.m_call_time=",pfoo9.ToString()); //--- Delete dynamically created arrays delete pfoo6; delete pfoo7; //delete pfoo8; // You do not need to delete pfoo8 explicitly, since it points to the automatically created object foo1 //delete pfoo9; // You do not need to delete pfoo9 explicitly. since it points to the same object as pfoo7 }
اگر این رشتهها را از کامنت خارج کنید
//CFoo foo_array[3]; // This variant cannot be used - a default constructor is not set //
یا
//CFoo foo_dyn_array[]; // This variant cannot be used - a default constructor is not set //
سپس کامپایلر برای آنها خطای “default constructor is not defined” را برمیگرداند.
- اگر یک کلاس دارای سازنده تعریف شده توسط کاربر(user-defined constructor) باشد، default constructor توسط کامپایلر تولید نمیشود. توجه به این نکته الزامیست که تفاوتی ندارد که user-defined constructor از جنس Default constructor و یا Parametric constructor باشد.، به هر روی در صورت تعریف constructor توسط کاربر، default constructor توسط کامپایلر تولید نمیشود.؛ این بدان معناست که اگر parametric constructor در یک کلاس تعریف شود اما default constructor تعریف نشده باشد، نمیتوانید آرایههای اشیاء این کلاس را تعریف کنید. کامپایلر یک خطا برای این اسکریپت برمیگرداند. :
اگر parametric constructor در یک کلاس تعریف شود اما default constructor تعریف نشده باشد، نمیتوانید آرایههای اشیاء این کلاس را تعریف کنید.
//+------------------------------------------------------------------+ //| A class without a default constructor | //+------------------------------------------------------------------+ class CFoo { string m_name; public: CFoo(string name) { m_name=name;} }; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- Get the "default constructor is not defined" error during compilation CFoo badFoo[5]; }
در کد بالا نیز کامپایلر خطای “Default constructor is not defined” را برمیگرداند. میتوان برای جلوگیری از این اررور کد را به شکل زیر اصلاح کرد.
//+------------------------------------------------------------------+ //| A class without a default constructor | //+------------------------------------------------------------------+ class CFoo { string m_name; public: //--- Default constructor CFoo(void) {}; //--- Parametric constructor CFoo(string name) { m_name = name;} }; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- CFoo badFoo[5]; }
در این مثال، کلاس CFoo دارای یک parametric constructor تعریف شده است – در چنین مواردی، کامپایلر یک default constructor را به طور خودکار در طول کامپایل ایجاد نمیکند. در همان زمان که آرایهای از اشیاء را تعریف میکنید، فرض بر این است که همه اشیا باید به طور خودکار ایجاد و مقداردهی اولیه شوند.
در هنگام راهاندازی خودکار یک شی، لازم است یک default constructor فراخوانی شود، اما از آنجایی که constructor پیشفرض به صراحت(explicitly) تعریف نشده و به دلیلی که دکرش رفت به طور خودکار نیز توسط کامپایلر تولید نمیشود، ایجاد چنین شیای غیرممکن است. به همین دلیل کامپایلر در مرحله کامپایل خطا ایجاد میکند.
- نکته ی دیگر این که منطقا تا قبل از ساخت instance از constructor مطلوب باید بدنهای برای تابع این constructor حال خواه در داخل و خواه خارج کلاس تعریف شود. :
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+ class MyDateClass { private: int m_year; // Year int m_month; // Month int m_day; // Day of the month int m_hour; // Hour in a day int m_minute; // Minutes int m_second; // Seconds public: //--- Default constructor MyDateClass(void); //--- Parametric constructor MyDateClass(int h, int m, int s); }; //+------------------------------------------------------------------+ void OnStart() { //--- MyDateClass obj(); MyDateClass *test = new MyDateClass(); } //+------------------------------------------------------------------+ MyDateClass::MyDateClass(void) { Print(__FUNCTION__); } //+------------------------------------------------------------------+
در این مثال برای این که هر یک از دو سطر داخل OnStart Event Handling منجر به اررور نشود. باید تعریف بدنه constructor را اضافه کرد.
در واقع یعنی در این حالت به اررور “function ‘CFoo::CFoo’ must have a body” برمیخوریم. :
//+------------------------------------------------------------------+ //| A class without a default constructor | //+------------------------------------------------------------------+ class CFoo { string m_name; public: //--- Default constructor CFoo(void); //--- Parametric constructor CFoo(string name) { m_name = name;} }; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- CFoo badFoo[5]; }
در مقالات بعدی آموزش ام کیو ال، مطالب آموزش کلاس در زبان MQL پی گرفته و سایر نکات مربوط به این بخش را شرح خواهیم داد.
همچنین میتوانید از سسله مقالات آموزش Python سایت جهان بورس استفاده نمایید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.