کلاس در زبان 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 سایت جهان بورس استفاده نمایید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.