龙听期货论坛's Archiver

龙听 发表于 2020-3-23 10:37

MQL5 入门知识汇总

点操作符 ( . )

对于直接访问结构和类的公共成员 时,使用点操作符。

语法:Variable_name_of_structure_type.Member_name

struct SessionTime

   {

   string sessionName;

   int   startHour;

   int   startMinutes;

   int   endHour;

   int   endMinutes;

   } st;

st.sessionName="Asian";

st.startHour=0;

st.startMinutes=0;

st.endHour=9;

st.endMinutes=0;

范围解析操作符 ( :: )

mql5中每个函数都有其执行范围。例如,Print()系统函数可以在全局范围使用。Imported函数导入时使用。classes函数用在类的范围。

语法:[Scope_name]::Function_name(parameters)

如果没有范围名,就属于全局范围函数。如果没有范围解析操作,可以在最近范围内找到函数。如果本地范围没有函数,需要全局搜寻函数。

范围解析操作也用在确定函数-类成员。

type Class_name::Function_name(parameters_description)

   {

// 函数主体

   }

   在一个程序使用不同执行上下文的几个同名函数可能会引起歧义。无明确范围规范的函数调用的优先顺序如下:

1.类方法。如果在类中设置了无指定名称的函数,那么移到下一级别。

2.MQL5 函数。如果语言没有这种函数,那么移到下一级别。

3.用户定义全局函数。如果没有找到有指定名称的函数,那么移到下一级别。

4.导入函数。如果没有发现有指定名称的函数,那么编译器返回一个错误。

若要避免函数调用歧义,就要使用范围解析操作,始终明确指定函数范围。class CCheckContext

  {

  int   m_id;

public:

       CCheckContext() { m_id=1234; }

protected:

  int   GetLastError() { return(m_id); }

  };

class CCheckContext2 : public CCheckContext

  {

   int  m_id2;

public:

        CCheckContext2() { m_id2=5678; }

  void  Print();

protected:

  int   GetLastError() { return(m_id2); }

  };

void CCheckContext2::Print()

  {

   ::Print("Terminal GetLastError",::GetLastError());

   ::Print("kernel32 GetLastError",kernel32::GetLastError());

   ::Print("parent GetLastError",CCheckContext::GetLastError());

   ::Print("our GetLastError",GetLastError());

}  

//+------------------------------------------------------------------+

//| 脚本程序启动函数                                                                             |

//+------------------------------------------------------------------+

void OnStart()

  {

//---

   CCheckContext2 test;

  test.Print();

  }

对象创建操作符new

new 操作符自动创建一个相应大小的对象,称为对象构造函数并回转已经创建的对象描述符。失败的情况下,操作符返回一个与常量NULL相比较的null描述符。

new操作符仅能用于类对象。不能应用于结构。操作符不用于创建对象数组。若要做这个,使用 ArrayResize() 。

//+------------------------------------------------------------------+

//| 图形创建                                                                                       |

//+------------------------------------------------------------------+

void CTetrisField::NewShape()

  {

  m_ypos=HORZ_BORDER;

//--- 随机创建7个可能形状中的一个

   int nshape=rand()%7;

  switch(nshape)

    {

     case 0: m_shape=new CTetrisShape1; break;

     case 1: m_shape=new CTetrisShape2; break;

     case 2: m_shape=new CTetrisShape3; break;

     case 3: m_shape=new CTetrisShape4; break;

     case 4: m_shape=new CTetrisShape5; break;

     case 5: m_shape=new CTetrisShape6; break;

     case 6: m_shape=new CTetrisShape7; break;

    }

//--- 绘画

  if(m_shape!=NULL)

    {

     //--- 预置

     m_shape.SetRightBorder(WIDTH_IN_PIXELS+VERT_BORDER);

     m_shape.SetYPos(m_ypos);

     m_shape.SetXPos(VERT_BORDER+SHAPE_SIZE*8);

     //--- 绘画

     m_shape.Draw();

    }

  }

对象删除操作符 delete

delete操作符删除通过new操作符创建的对象,称为相关的类析构函数并释放由对象占据的内存。现存对象的真实析构函数用作操作对象。delete操作执行后,对象析构函数无效 。

//--- 删除图形

  delete m_shape;

  m_shape=NULL;

//--- 创建一个新图形

  NewShape();

引用与修饰符&

简单类型参数能够通过值和引用传送,而复合类型参数经常通过引用传送。若使编译器了解参数是通过引用传送,需要在参数前加上&符号。

通过引用传送参数意味着传送变量地址,这就是通过引用传送的参数的所有改变能够马上在变量源中反映出来的原因。使用通过引用传送的参数,一个函数可以同时得出几种结果。为防止引用传送的参数改变,使用常量修饰符。

class CDemoClass

  {

private:

   double  m_array[];

public:

  void   setArray(double &array[]);

  };

//+------------------------------------------------------------------+

//| 填充数组                                                                                       |

//+------------------------------------------------------------------+

void  CDemoClass::setArray(double &array[])

  {

  if(ArraySize(array)>0)

    {

    ArrayResize(m_array,ArraySize(array));

    ArrayCopy(m_array, array);

    }

  }

目标指针

在MQL5中,有可能动态地创造复杂形势的目标,被新操作执行,创造目标返回一个描述符号,描述符号占用8字节。

MyObject* hobject= new MyObject();

class Foo

  {

public:

  string  m_name;

  int   m_id;

   static int  s_counter;

   //--- 构造函数和析构函数

          Foo(void){Setup("noname");};

          Foo(string name){Setup(name);};

          ~Foo(void){};

   //--- 初始化Foo类型对象

  void   Setup(string name)

    {

     m_name=name;

     s_counter++;

     m_id=s_counter;

    }

  };

int Foo::s_counter=0;

//+------------------------------------------------------------------+

//| 脚本程序开始函数                                                                           |

//+------------------------------------------------------------------+

void OnStart()

  {

//--- 声明一个自动创建的对象变量

   Foo foo1;

//--- 引用传递对象变量

  PrintObject(foo1);

//--- 声明对象指针,使用'new'操作符创建它

   Foo *foo2=new Foo("foo2");

//--- 引用传递对象指针的变量

  PrintObject(foo2); // 对象指针根据编译器自动转换

//--- 声明Foo类型对象的数组

   Foo foo_objects[5];

//--- 传递对象数组变量

  PrintObjectsArray(foo_objects); // 传递对象数组的单独函数

//--- 声明Foo类型对象的指针数组

   Foo *foo_pointers[5];

   for(int i=0;i<5;i++)

    {

     foo_pointers[i]=new Foo("foo_pointer");

    }

//--- 传递指针数组变量

  PrintPointersArray(foo_pointers); // 传递数组指针分隔函数

//--- 终止前强制删除创建为指针的对象

  delete(foo2);

//--- 删除指针数组

   int size=ArraySize(foo_pointers);

   for(int i=0;i<5;i++)

     delete(foo_pointers[i]);

  }

//+------------------------------------------------------------------+

//| 始终通过引用传递对象                                                                       |

//+------------------------------------------------------------------+

void PrintObject(Foo &object)

  {

   Print(__FUNCTION__,": ",object.m_id," Object name=",object.m_name);

  }

//+------------------------------------------------------------------+

//| 传递对象数组                                                                                  |

//+------------------------------------------------------------------+

void PrintObjectsArray(Foo &objects[])

  {

   int size=ArraySize(objects);

   for(int i=0;i

    {

     PrintObject(objects[i]);

    }

  }



//+------------------------------------------------------------------+

//| 传递对象指针数组                                                                             |

//+------------------------------------------------------------------+

void PrintPointersArray(Foo* &objects[])

  {

   int size=ArraySize(objects);

   for(int i=0;i

    {

     PrintObject(objects[i]);

    }

  }

关键字 this

   关键字this意在获得目标的引用,可以在类或者结构函数里得到。this经常引用到目标中,并在此函数中使用,表达式GetPointer(this) 给出目标指针,其成员为完成GetPointer()的函数。在MQL5中,函数不能返回对象,但是它们能返回目标指针。

class CDemoClass

  {

private:

  double           m_array[];

public:

  void             setArray(double &array[]);

  CDemoClass      *getDemoClass();

  };

//+------------------------------------------------------------------+

//| 填充数组                                                                                        |

//+------------------------------------------------------------------+

void  CDemoClass::setArray(double &array[])

  {

  if(ArraySize(array)>0)

    {

     ArrayResize(m_array,ArraySize(array));

     ArrayCopy(m_array,array);

    }

  }

//+------------------------------------------------------------------+

//| 返回它自己的指针                                                                            |

//+------------------------------------------------------------------+

CDemoClass *CDemoClass::getDemoClass(void)

  {

  return(GetPointer(this));

  }

架构(类与其类似)

创建框架:struct + 架构名称。

创建架构变量:架构名称 + 变量名称。

访问变量中的架构成员:变量名称 + . + 成员名称。

架构中不能有虚拟函数。

new不能用于架构。

//---创建架构

struct trade_settings

   {

   double take;// 利润固定价格值

   double stop;// 受保护的止损价格值

  uchar  slippage;// 可接受的下降值

   };

//--- 创建和初始化交易设置类型的变量

trade_settings my_set={0.0,0.0,5};//创建架构变量  

if (input_TP>0) my_set.take=input_TP;//访问并初始化架构变量中的架构成员

类和架构都有明确的构造函数和解构方法,如果构造函数定义明确,架构或类别变量的初始化进行初始化序列是不可能的。

struct trade_settings

  {

   double  take;// 利润固定价格值

   double  stop;// 受保护的止损价格值

   uchar  slippage;// 可接受的下降值

   //--- 构造函数

         trade_settings() { take=0.0; stop=0.0; slippage=5; }

   //--- 析构函数

        ~trade_settings() { Print("This is the end"); }

  };

//--- 编译器生成一个无法初始化的错误信息

trade_settings my_set={0.0,0.0,5};

构造函数与析构函数

构造函数不需要返回类型。

构造函数与类的名称匹配。

构造函数分为参数构造函数和缺省构造函数。

每个类可以有多个构造函数。

构造函数可以在类描述中声明然后定义主体。

//+------------------------------------------------------------------+

//| 处理日期的类                                                                                  |

//+------------------------------------------------------------------+

class MyDateClass

  {

private:

  int   m_year;// 年

  int   m_month;// 月

  int   m_day;// 几月几日

  int   m_hour; // 某天几时

  int   m_minute; // 分钟

  int   m_second;// 秒

public:

   //--- 缺省构造函数

        MyDateClass(void);

   //--- 参数构造函数

        MyDateClass(int h,int m,int s);

  };

//+------------------------------------------------------------------+

//| 默认构造函数                                                                                  |

//+------------------------------------------------------------------+

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__);

  }

//+------------------------------------------------------------------+

//| 参数构造函数                                                                                  |

//+------------------------------------------------------------------+

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__);

  }

在默认构造函数,类的所有成员都使用TimeCurrent() 函数,在参数构造函数,只有时分秒值在使用。其他的类成员将自动初始化当前日期。

当初始化类的对象数组时,默认构造函数有一个特殊用途。所有参数都有默认值的构造函数,并不是默认构造函数。

//+------------------------------------------------------------------+

//| 默认构造函数的类                                                                            |

//+------------------------------------------------------------------+

class CFoo

  {

  datetime   m_call_time;// 最近一次对象调用时间

public:

   //--- 带有默认值参数的构造函数不是默认构造函数

   CFoo(const datetime t=0){m_call_time=t;};

   //--- 复制构造函数

   CFoo(const CFoo &foo){m_call_time=foo.m_call_time;};

  };

//+------------------------------------------------------------------+

//| 脚本程序开始函数                                                                             |

//+------------------------------------------------------------------+

void OnStart()

  {

// CFoo foo;// 该变量不能使用 - 没有设置默认构造函数

//--- 创建 CFoo 对象的可能选项

   CFoo foo1(TimeCurrent());// 参数构造函数的显式调用

   CFoo foo2();// 带有默认参数的参数构造函数的显式调用

   CFoo foo3=D'2009.09.09'; // 参数构造函数的隐式调用

   CFoo foo40=(foo1);// 复制构造函数的显式调用

   CFoo foo41=foo1;// 复制构造函数的隐式调用

   CFoo foo5;//默认构造函数的显式调用(如果没有默认构造函数那么带有默认值的参数构造函数被调用)

//--- 接收 CFoo 指针的可能选项

   CFoo *pfoo6=new CFoo();// 动态创建对象和接收其指针

   CFoo *pfoo7=new CFoo(TimeCurrent());// 另一个动态对象创建的选项

   CFoo *pfoo8=GetPointer(foo1);// 现在pfoo8 指向对象foo1

   CFoo *pfoo9=pfoo7;// pfoo9 和 pfoo7 指向一个和相同的对象

// CFoo foo_array[3];// 该选项不能使用 - 没有指定默认构造函数

//--- 显示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 pfoo6;

   delete pfoo7;

//删除 pfoo8;// 您不需要一定删除pfoo8,因为它指向自动创建的对象foo1

//删除 pfoo9;// 您不需要一定删除pfoo9,因为它指向pfoo7相同的对象

  }

如果您取消这些字符串

//CFoo foo_array[3];// 该变量不能使用 - 没有设置默认构造函数

//CFoo foo_dyn_array[];//该变量不能使用 - 没有设置默认构造函数

然后编译器将会返回一个错误“默认构造函数未定义”。

类型的密封和扩展

密封就是当向用户定义类型提供端口时,隐藏执行细节的能力。

Private成员,只能通过类成员函数接入。

Protected成员,可以通过类成员函数接入或者通过继承类成员函数接入。

public成员,可以通过类声明范围内任意一个函数接入。

struct Name

{

  string  first_name; // 名称

  string  last_name; // 上一个 名称

};

class CPerson

{

protected:

  Name  m_name; // 名称

public:

  void   SetName(string n);

  string  GetName(){return(m_name.first_name+" "+m_name.last_name);}

private:

  string  GetFirstName(string full_name);

  string  GetLastName(string full_name);

};

void CPerson::SetName(string n)

{

  m_name.first_name=GetFirstName(n);

  m_name.last_name=GetLastName(n);

}

string CPerson::GetFirstName(string full_name)

{

   int pos=StringFind(full_name," ");

   if(pos>0) StringSetCharacter(full_name,pos,0);

  return(full_name);

}

string CPerson::GetLastName(string full_name)

{

   string ret_string;

   int pos=StringFind(full_name," ");

  if(pos>0) ret_string=StringSubstr(full_name,pos+1);

  else     ret_string=full_name;

  return(ret_string);

}

继承算法

1.对象创建时首先调用基本类构造函数,然后调用衍生类的构造函数。

2.对象毁坏时首先调用衍生类的析构函数,然后调用基本类析构函数。

3.基本类的构造函数和析构函数不能继承。

4.衍生类是基本类的变体,它继承了基本类的protected 和 public构件。

5.protected继承中,基本类public和protected构件成为衍生类protected构件。

6.private 继承中,基本类public 和protected构件成为衍生类private构件。

让我们创建一个基本类 CShape,它包括描述图形最常用的构件。这些构件描述任何图形所特有的属性-图像类型和定位点主坐标。

//--- 基本类的形状

class CShape

{

protected:

  int   m_type;// 形状类型

  int   m_xpos; // 基本点的X - 坐标

  int   m_ypos; // 基本点的Y - 坐标

public:

        CShape(){m_type=0; m_xpos=0; m_ypos=0;} // constructor

   void   SetXPos(int x){m_xpos=x;} // 设置 X

  void   SetYPos(int y){m_ypos=y;} // 设置 Y

};

下一步,创建基本类衍生出的新类,这里我们可以添加说明类的必要的字段。对于圆形添加包括半径值构件是必须的。正方形以边值为特点。因此,由继承基本类CShape而衍生的类如下声明:

//--- 派生类 圆形

class CCircle : public CShape // 冒号后定义基本类

{                                   

private:

   int m_radius;// 圆弧半径

public:

       CCircle(){m_type=1;}// 构造函数, 类型 1

};

//--- 派生类 方形

class CSquare : public CShape // 冒号后定义基本类

{                                   

private:

   int m_square_side; // 方形的边

public:

       CSquare(){m_type=2;} // 构造函数,类型2

};



任何继承类型中,只有public 和 protected访问说明符声明的基类成员可用衍生类。

//+------------------------------------------------------------------+

//|一些访问类型的示例类                                        |

//+------------------------------------------------------------------+

class CBaseClass

{

private: //--- 从衍生类,private成员不可用         

  int   m_member;

protected: //--- 从基类及其衍生类,protected方法不可用     

  int  Member(){return(m_member);}

public: //--- 类构造函数可用于类的所有成员            

       CBaseClass(){m_member=5;return;};

private: //--- 将值分配给m_member的private方法            

  void  Member(int value) { m_member=value;};

};

//+------------------------------------------------------------------+

//| 有错误的衍生类                                            |

//+------------------------------------------------------------------+

class CDerived: public CBaseClass // 由于默认的原因,public继承规范可以忽略。

{

public:

   void Func() // 在衍生类中,定义调用到基类成员的函数。

    {

     //--- 试图修改基类的private成员

     m_member=0;       // 错误,基类private成员不可用

     Member(0);        // 错误,基类的private方法不可用在衍生类

     //--- 阅读基类的成员

     Print(m_member);   // 错误,基类的private成员不可用

     Print(Member());   // 没有错误,protected方法可从基类及其衍生类使用

    }

};

如果是protected继承类型的情况下,所有public和protected访问权限的基类成员都会成为protected。这就意味着如果public基类的数据成员和方法从外部访问,那么protected继承类型的情况下,他们只能从衍生类及其衍生品的类中使用。

//+------------------------------------------------------------------+

//| 一些访问类型的示例类                                       |

//+------------------------------------------------------------------+

class CBaseMathClass

{

private: //--- private成员不可从衍生类使用

   double  mPi;

public: //--- 获取和设置mPi值

  void  SetPI(double v){m_Pi=v;return;};

  double  GetPI(){return m_Pi;};

public: // 类构造函数可用于所有成员

         CBaseMathClass() {SetPI(3.14); PrintFormat("%s",__FUNCTION__);};

};

//+------------------------------------------------------------------+

//| 一个衍生类,在此m_Pi不能修改                                 |

//+------------------------------------------------------------------+

class CProtectedChildClass: protected CBaseMathClass // Protected继承类型

{

private:

  double  m_radius;

public: //--- 衍生类中的Public方法

  void   SetRadius(double r){m_radius=r; return;};

  double  GetCircleLength(){return GetPI()*m_radius;};

};

//+------------------------------------------------------------------+

//| 脚本启动函数                                             |

//+------------------------------------------------------------------+

void OnStart()

{

//--- 创建衍生类时,基类的构造函数将自动调用

   CProtectedChildClass pt;

//--- 指定半径

  pt.SetRadius(10);

  PrintFormat("Length=%G",pt.GetCircleLength());

//--- 如果评论下面的字符串,我们在编译阶段将得到一个错误,因为SetPi()现在是protected的类型

// pt.SetPI(3);

//--- 现在声明基类变量,尝试将Pi常量设置等于10

   CBaseMathClass bc;

  bc.SetPI(10);

//--- 下面是结果

  PrintFormat("bc.GetPI()=%G",bc.GetPI());

};

如果是private继承类型,所有public和protected访问权限的基类成员都会成为private,并且在进一步继承中无法进行调用。

多态性

有关每个数组元素将包括的对象类型决策将在程序执行期间直接采用。这包括动态创建合适的类的对象,因此需要使用对象指针来替代对象。

new操作符用于动态创建对象。每个这样的对象都必须独立且明确地使用delete操作符删除。

//+------------------------------------------------------------------+

//| 脚本程序开始函数                                         |

//+------------------------------------------------------------------+

void OnStart()

{

//--- 声明基本类型对象指针的数组

   CShape *shapes[5]; // CShape对象指针的数组

//--- 这里以衍生对象填充数组

//--- 声明指针到CCircle类型的对象

   CCircle *circle=new CCircle();

//--- 在圆形指针设置对象属性

  circle.SetRadius(2.5);

//--- 将指针值置于shapes[0]

  shapes[0]=circle;

//--- 创建另一个CCircle对象并写下其指针在shapes[1]

   circle=new CCircle();

  shapes[1]=circle;

  circle.SetRadius(5);

//--- 这里我们故意“忘记”设置shapes[2]值

//circle=new CCircle();

//circle.SetRadius(10);

//shapes[2]=circle;  

//--- 不使用的元素设置为NULL

  shapes[2]=NULL;

//--- 创建CSquare对象并写下其指针在shapes[3]

   CSquare *square=new CSquare();

  square.SetSide(5);

  shapes[3]=square;

//--- 创建CSquare对象并写下其指针到shapes[4]

   square=new CSquare();

  square.SetSide(10);

  shapes[4]=square;

//--- 我们有一组指针,获得其大小

   int total=ArraySize(shapes);

//--- 通过数组的所有指针循环通过

   for(int i=0; i<5;i++)

    {

     //--- 如果指定指数的指针有效

     if(CheckPointer(shapes[i])!=POINTER_INVALID)

       {

        //--- 记录类型和正方形

        PrintFormat("The object of type %d has the square %G",

              shapes[i].GetType(),

              shapes[i].GetArea());

       }

     //--- 如果指针类型POINTER_INVALID

     else

       {

        //--- 错误的通知

        PrintFormat("Object shapes[%d] has not been initialized! Its pointer is %s",

                     i,EnumToString(CheckPointer(shapes[i])));

       }

    }

//--- 我们必须删除所有已创建的动态对象

   for(int i=0;i

    {

     //--- 我们只可以删除POINTER_DYNAMIC类型指针的对象

     if(CheckPointer(shapes[i])==POINTER_DYNAMIC)

       {

        //--- 删除的通知

        PrintFormat("Deleting shapes[%d]",i);

        //--- 通过指针删除对象

        delete shapes[i];

       }

    }

}

请注意,当使用delete操作符删除对象时,必须检查指针类型。只有POINTER_DYNAMIC 指针对象可以使用delete删除。对于其他类型的指针,将返回错误。

重载函数与重载

通常函数名反映它的作用。一般说来,可读程序包括各种挑选出来的标识符 。有时不同的函数用于同样的作用。重载就是一个函数定义多值。根据函数接收的自变量类型选择特定的值。基于调用函数时对应的自变量列表选择特定的函数,到函数说明参数列表。

1.匹配严格(尽可能)。

2.尝试标准类型提高。

3.尝试标准类型转换。

在一个类中定义两个或者以上同名类函数是可能的,但是会有不同数量的参量。当这个发生时,类函数就称为重载而这样的过程被称为类函数重载。如果调用的函数无准确匹配,编译器就会在三个连续阶段搜索适合的函数:

1.类函数中搜索。

2.基本类函数中搜索,按照最近到最开始顺序。

3.其他函数中搜索。

类/结构的静态成员

类成员可以使用存储类修饰符static进行声明。这些数据成员通过该类的所有实例共享并存储在一个地方。为每个类对象变量创建非静态数据成员。

由于静态类成员不依赖于具体实例,则对它的引用如下:

class_name::variable

类的静态成员必须以所需的值进行显式初始化。为此,它必须在全局范围声明和初始化。静态成员初始化的顺序对应其在全局范围声明的顺序。

//+----------------------------------------------------------------+

//| 类 "文本解析"                                                                             |

//+----------------------------------------------------------------+

class CParser

{

public:

static int  s_words;

static int  s_symbols;

//--- 构造函数和析构函数

       CParser(void);

       ~CParser(void){};

};

//--- 全局层面解析类静态成员的初始化

int CParser::s_words=0;

int CParser::s_symbols=0;

静态类成员可以通过const关键字来声明。这种静态常量必须在全局层面以const 关键字进行初始化:

//+-----------------------------------------------------------------+

//| 类 "Stack" 存储处理数据                                                               |

//+-----------------------------------------------------------------+

class CStack

{

public:

    CStack(void);

    ~CStack(void){};

private:

static const int s_max_length;// 最大存储栈能力

};

//--- 初始化CStack类的静态常量

const int CStack::s_max_length=1000;

类/结构的静态方法

在MQL5可以使用静态类型成员函数。在类内部的声明,静态修饰符必须在函数返回类型之前。

class CStack

{

public:

   //--- 构造函数和析构函数

         CStack(void){};

         ~CStack(void){};

   //--- 最大堆栈能力

   static int  Capacity();

private:

  int   m_length;// 存储栈中的元素数量

   static const int  s_max_length;// 最大存储栈能力

};

//+-----------------------------------------------------------------+

//| 返回堆栈中存储的元素的最大数量                                                     |

//+-----------------------------------------------------------------+

int CStack::Capacity(void)

{

  return(s_max_length);

}

//--- 初始化CStack 类的静态常量

const int CStack::s_max_length=1000;

//+-----------------------------------------------------------------+

//| 脚本程序起始函数                                                                          |

//+-----------------------------------------------------------------+

void OnStart()

{

//--- 声明 CStack 类型变量  

   CStack stack;

//--- 调用对象的静态方法  

  Print("CStack.s_max_length=",stack.Capacity());

//--- 它也可以按以下方式调用,因为方法是静态的,无需对象的存在  

  Print("CStack.s_max_length=",CStack::Capacity());

  }

const 修饰符方法被称为常量并且不能修改类的隐式成员。声明类的常量函数和常量参数被称为const-correctness控制。通过这个控制,可以保证,编译器将确保对象值的一致性并且如果有什么问题,在编译过程中将会返回一个错误。

参数列表进入类声明以后才会放置const修饰符。类以外的定义也应该包括 const 修饰符:

//+-----------------------------------------------------------------+

//| “矩形”类                                                                                   |

//+-----------------------------------------------------------------+

class CRectangle

{

private:

  double   m_width;// 宽度

  double   m_height;// 高度

public:

   //--- 构造函数和析构函数

  CRectangle(void):m_width(0),m_height(0){};

   CRectangle(const double w,const double h):m_width(w),m_height(h){};

  ~CRectangle(void){};

   //--- 计算区域

   double  Square(void) const;

   static doubleSquare(const double w,const double h);

{ return(w*h); }

};

//+-----------------------------------------------------------------+

//| 返回“矩形”对象区域                                                                   |

//+-----------------------------------------------------------------+

double CRectangle::Square(void) const

{

  return(Square(m_width,m_height));

}

//+-----------------------------------------------------------------+

//| 返回两变量的产品                                                                          |

//+-----------------------------------------------------------------+

static double CRectangle::Square(const double w,const double h)

{

  return(w*h);

}

//+-----------------------------------------------------------------+

//| 脚本程序起始函数                                                                          |

//+-----------------------------------------------------------------+

void OnStart()

{

//--- 创建等于5和6的矩形

   CRectangle rect(5,6);

//--- 用常量方法找出矩形区域

  PrintFormat("rect.Square()=%.2f",rect.Square());

//--- 通过类CRectangle的静态方法找出产品数量

PrintFormat("CRectangle::Square(2.0,1.5)=%f",CRectangle::Square(2.0,1.5));

}

页: [1]