MQL5教程 02 标准语法

一、事件处理函数

1、OnInit / OnDeinit / OnTick

OnInit:当指标或EA第一次加载时,执行该函数。
OnDeinit:卸载指标或EA,或者关闭加载该指标或EA的图表时,执行该函数。
OnTick:在价格每波动一次,执行一次该函数。

int OnInit()
  {
      printf("init");
      return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
      printf("deinit");
  }

void OnTick()
  {
      printf("tick");
  }

2、OnTimer

计时器设定的固定时间间隔,执行该函数。

int OnInit()
  {
      EventSetTimer(3); // 设定定时器,每隔3s,执行一次OnTimer函数
      printf("init");
      return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
      printf("deinit");
  }

void OnTick()
  {
  
      if(TimeLocal()>= D'2025.2.6 17:13:00')
      {
         EventKillTimer(); // 清除定时器
      }
  }
  
void OnTimer()
   {
      printf(TimeToString(TimeLocal(), TIME_DATE|TIME_SECONDS));
   }

3、OnTrade / OnTradeTransaction

OnTrade:对即时交易或者挂单进行开仓、平仓、修改订单,都执行该函数。由于该函数难以把控,一般不使用。
OnTradeTransaction:事件触发条件同 OnTrade

int OnInit()
  {
   printf("init");
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   printf("deinit");
  }

void OnTick()
  {
  }

void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest&     request,
                        const MqlTradeResult&      result)
  {
   if(trans.type==TRADE_TRANSACTION_REQUEST)
   // trans.type == TRADE_TRANSACTION_REQUEST: 检查交易类型是否为交易请求。
     {
      if(request.action==TRADE_ACTION_DEAL && request.type==ORDER_TYPE_BUY)
      // TRADE_ACTION_DEAL 即时交易
      // ORDER_TYPE_BUY 订单类型是买单 注:空单平仓视为开多单
        {
         Alert("你已经开多单");
        }
     }
  }

4、OnChartEvent

OnChartEvent:当在图表上进行一些操作时,触发事件,执行该回调函数。

int OnInit()
  {
   printf("init");
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   printf("deinit");
  }

void OnTick()
  {
  }

void  OnChartEvent(
   const int       id,
   const long&     lparam,
   const double&   dparam,
   const string&   sparam)
  {
   if(id==CHARTEVENT_CLICK)
     {
      Alert("你单击了鼠标"+"x:"+lparam+"y:"+dparam);
     }
  }

5、OnTester

OnTester:在EA交易测试历史数据完毕后,执行该函数。

int OnInit()
  {
   printf("init");
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   printf("deinit");
  }

void OnTick()
  {
   printf("hello");
  }

double  OnTester()
  {
   printf("执行完了!");
   return(11.0);
  }

6、OnTesterInit / OnTesterPass / OnTesterDeinit

EA优化时,触发这些函数。
详细说明,暂略。

7、OnBookEvent

OnBookEvent:在市场深度变化时触发。

int OnInit()
  {
   printf("init");
   MarketBookAdd(Symbol());
   // MarketBookAdd() 将一个交易品种的市场深度数据添加到系统中
   // Symbol() 返回当前图表的交易品种名称。
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   printf("deinit");
  }

void OnTick()
  {
   printf("hello");
  }

void  OnBookEvent(const string&  symbol)
  {
   printf(symbol+"这个货币市场深度发生了变化");
  }

8、OnCalculate

OnCalculate:指标专有的事件处理函数,每个新的 tick 到来,触发一次该函数。

int OnInit()
  {
   return(INIT_SUCCEEDED);
  }

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   printf(open[1]);
   return(rates_total);
  }

9、OnStart

OnStart:脚本专有的事件处理函数,加载脚本后,只执行一次。

int OnStart()
  {
   Alert("脚本执行完了!");
   return(1);
  }

二、初级语法

1、常用基本数据类型

整型 int
浮点型 double
字符串 string
颜色 color
时间 datetime


int OnStart()
  {
   int      a = 123;
   double   b = 1.23;
   string   c = "abc";
   color    d = clrDarkViolet;
   // 颜色也可以定义为C'R,G,B',取值范围为0-255
   datetime e = D'2025.02.16 05:05';
   
   return(1);
  }

2、常量

(1)标准常量

系统自带的的常量。

int OnStart()
  {
   int x = PERIOD_M15;  // PERIOD_M15为标准常量
   
   return(1);
  }

(2)自定义常量

#define changliang "abc"

int OnStart()
  {
   string s = changliang;
   
   return(1);
  }

3、变量

(1)预定义变量

每个预定义变量都对应一个函数,以后编程时,可以直接使用该函数,来代替预定义变量。

int OnStart()
  {
   int f = _Digits; // 预定义变量
   int g = Digits();
   
   return(1);
  }

(2)自定义变量

自己定义的变量,如上述的 int a = 123;,a就为自定义变量。

4、函数

(1)系统自带的函数

int OnStart()
  {
   Alert("报警");
   
   return(1);
  }

(2)自定义函数

int OnStart()
  {
   int a = 12;
   int b = 2;
   int s = add(a,b);
   
   return(1);
  }

int add(int x, int y)
  {
   return(x+y);
  }

(3)函数转换

函数转化函数用来进行数据类型转换。

int OnStart()
  {
   int a = 12;
   string shijian = "2025.02.16 21.44";
   
   string k = IntegerToString(a);
   datetime j = StringToTime(shijian);
   
   string g = StringFormat("姓名:%s 年龄:%d 身高:%.2f","LMX",18,170.555);
   printf("姓名:%s 年龄:%d 身高:%.2f","LMX",18,170.555); // 输出内容同g
   return(1);
  }

(4)字符串函数

字符串函数用来处理字符串

int OnStart()
  {
   string a1 = "asgqwer0";
   int ret1 = StringFind(a1,"gq",0);   // 返回匹配字符串的位置索引
   string b1 = StringSubstr(a1,2,3);   // gqw
   
   string c1 = "张三,18,170.5";
   string c2[];
   StringSplit(c1, ',', c2);
   
   return(1);
  }

5、变量和函数的作用域

(1)外部参数变量

外部参数变量也是全局变量,它的值通常在运行时通过用户界面(如弹出框)进行设置。

#property script_show_inputs  // 在脚本运行时显示输入参数窗口
input double lots=0.1;  // 外部参数变量

int OnStart()
  {
   Alert(lots);
   
   return(1);
  }

(2)全局变量

全局变量可以被所有函数使用。

int magic = 456; // 全局变量

int OnStart()
  {
   printf("%d",magic);
   a();
   return(1);
  }
  
void a()
  {
   printf("%d",magic+1);
  }

(3)局部变量

函数内部定义的变量,包括形参。局部变量只能在函数内部使用。

(4)函数引用参数变量

引用参数变量相当于给被引用变量起了一个别名,实际上引用参数变量和被引用变量指向同一块内存空间。

int OnStart()
  {
   int a = 11;
   int b = 22;
   mul(a, b);
   printf("a=%d,b=%d",a,b); // a=110,b=22
  
   return(1);
  }
  
void mul(int &x, int y)
  {
   x = x*10;
   y = y*10;
  }

三、中级语法

1、程序端全局变量

程序端全局变量和我们自定义的普通全局变量是不一样的,它存储在平台的内存中,并且可以跨不同的脚本或EA共享。它需要用GlobalVariableSet()创建。

// 防止多次开单示意程序
// 即使退出MT5程序,程序端全局变量name + "duook"的值也会保存

string name;
int magic = 123;

int OnInit()
  {
   name = MQLInfoString(MQL_PROGRAM_NAME) + Symbol() + IntegerToString(magic);
   // MQLInfoString(MQL_PROGRAM_NAME) 返回已启动的MQL5程序的名称

   if(GlobalVariableCheck(name + "duook") == false) // 检查程序端全局变量是否存在
     {
      GlobalVariableSet(name + "duook", 0); // 将程序端全局变量name + "duook"的值设置为0
     }

   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   printf("deinit");
  }

void OnTick()
  {
   if(GlobalVariableGet(name + "duook") == 0)
    {
     // 在这里可以写开多单的代码
     GlobalVariableSet(name + "duook", 1);
    }
  }

2、枚举类型

// 自定义枚举类型duokong
// 将duo设为1,默认为0。kong默认为上一个枚举常量加+1,以此类推。
// 枚举常量的注释会在加载EA弹出的窗口中显示出来
enum duokong   
  {
   duo = 1, // 只开多
   kong,    // 只开空
   duokong  // 多空都可以开
  };
  
// 定义枚举类型为duokong的变量openDirection,默认值设为duo
input duokong openDirection=duo;

int OnInit()
  {
   Print(openDirection);
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   printf("deinit");
  }

void OnTick()
  {

  }

在这里插入图片描述


也可以使用系统预定义的枚举类型

input ENUM_TIMEFRAMES period=PERIOD_H1;

int OnInit()
  {
   Print(period);
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   printf("deinit");
  }

void OnTick()
  {

  }

3、结构体类型

结构体成员可以是不同数据类型。

// 定义结构体类型kbar
struct kbar
  {
   double open;
   double close;
   double high;
   double low;
   datetime time;
   int vol;
  };

int OnInit()
  {
   kbar kb = {1.1,2.1,3.1,0.1,TimeCurrent(),55};  // 声明结构体变量kb,并且初始化
   kb.vol = 60;   // 修改结构体变量kb的成员vol的值。也可以直接用该方法对成员进行初始化。
   
   MqlRates mr;   // 使用系统预定义的结构体类型MqlRates,去定义结构体变量mr
   mr.open= 1.1;  // 修改结构体变量成员open的值
   
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   printf("deinit");
  }

void OnTick()
  {

  }

4、数组

double a[10]; //定义double类型静态数组,元素从a[0]到a[9]

int OnInit()
  {
   double c[];    // 声明一个 double 类型的动态数组 c
   ArrayResize(c, 2);   // 调整数组 c 的大小为 2

   return(INIT_SUCCEEDED);
  }

int OnInit()
  {
   MqlRates rates[]; // 声明一个 MqlRates 类型的动态数组,用来存储历史数据
   ArraySetAsSeries(rates, true);   // 将数组设为倒序排列,最新的历史数据存放在数组的索引 0 位置
   
   CopyRates(NULL,0,0,100,rates);   // 获取 100 根 K 线数据,复制到数组rates中
   // NULL:表示当前图表的符号
   // 0:表示当前的时间周期
   // 0:表示从当前时间开始获取数据
   // 100:表示获取 100 根历史K线数据。
   // rates:存储获取到的数据的数组。
   
   double op = rates[0].open; // 获取第 0 根 K 线的开盘价,即当前K线开盘价

   return(INIT_SUCCEEDED);
  }

数组函数:

int OnInit()
  {
   int aok[5];
   ArrayInitialize(aok,1); // 将数组aok的元素都初始化为1
   ArrayFill(aok,2,2,3);   // 将数组aok的索引为2开始,两个元素的值设置为3

   return(INIT_SUCCEEDED);
  }

5、循环判断语句

int OnInit()
  {
   int a = 1;
   if(a > 1)
    {
      Print("大于");
    }
   else if(a == 1)
    {
     Print("等于");
    }
   else
    {
     Print("小于");
    }

   return(INIT_SUCCEEDED);
  }

int OnInit()
  {
   int w = 0;
   while(w<5)
    {
     Print(w);
     w++;
    }

   return(INIT_SUCCEEDED);
  }

int OnInit()
  {
   for(int i=0; i<10; i++)
    {
     Print(i);
    }

   return(INIT_SUCCEEDED);
  }

6、算术、关系、逻辑运算

比较简单,参考手册 MQL5参考 / 语言基础 / 运行式和表达式
其中,&& 为且,|| 为或。

int OnInit()
  {
   bool a = true;
   bool b = false;
   if(a || b)
    {
     Print("对");
    }
   else
    {
     Print("错");
    }

   return(INIT_SUCCEEDED);
  }

四、高级语法

1、类的创建

类一般放在 Include 文件夹下,并且一个类写在一个头文件中。
创建类可以在 Include 文件夹中,创建一个子文件夹 myClass,然后在 myClass 中创建一个类文件 testClass

在这里插入图片描述


在这里插入图片描述


myClass\testClass.mqh 代码如下:

class A
  {
   public:
      // 声明成员变量
      int b;
      double c;
      string d;
      
      // 声明成员函数
      int add(int x, int y)
        {
         printf(__FUNCTION__);   // 预定义宏,返回函数名称
         return(x+y);
        }
        
      A()   // 构造函数,实例对象创建时,被调用
        {
         printf(__FUNCTION__);
        }
        
      ~A()  // 析构函数,用于类的实例销毁时调用
        {
         printf(__FUNCTION__);
        }
  };

2、对象的定义

在栈上创建类的对象(推荐):

#include <myClass\testClass.mqh>
// 引入自定义类的头文件testClass.mqh
// 引入文件的根目录是Include

int OnStart()
  {
   A ac;
   return(1);
  }

对象 ac 的生命周期与当前作用域相关,当 OnStart() 函数执行完毕时,ac 对象会被销毁。


在堆上创建类的对象(动态定义):

#include <myClass\testClass.mqh>

int OnStart()
  {
   A *ac2 = new A();
   // new A() 会返回一个指向 A 类型对象的指针,这个指针被赋值给 ac2。
   delete ac2;
   // 由于 ac2 是指针类型,需要使用 delete 来手动释放堆上分配的内存,避免内存泄漏。
   // 不手动释放内存,即使脚本结束,也不会释放掉
   return(1);
  }

3、带参数的类和对象的定义

带一个参数:

类:

class A
  {
   public:
      // 声明成员变量
      int b;
      double c;
      string d;
      
      // 声明成员函数
      int add(int x, int y)
        {
         printf(__FUNCTION__);   // 预定义宏,返回函数名称
         return(x+y);
        }
        
      A(int x)
        {
         this.b = x;
         // this 是一个指针,它指向当前类的实例对象。
         // 在类的成员函数中,this 用来引用当前对象。
         // this 只能在成员函数中使用,用来指代当前正在调用该函数的对象。
         printf(__FUNCTION__);
        }
        
      ~A()  // 析构函数,用于类的实例销毁时调用
        {
         printf(__FUNCTION__);
        }
  };

对象:

#include <myClass\testClass.mqh>

int OnStart()
  {
   // A ac(2);
   A ac = 10;  // 效果同上
   Print(ac.b);

   return(1);
  }

带多个参数:
类:

class A
  {
   public:
      // 声明成员变量
      int b;
      double c;
      string d;
      
      // 声明成员函数
      int add(int x, int y)
        {
         printf(__FUNCTION__);   // 预定义宏,返回函数名称
         return(x+y);
        }
        
      A(int x, double y, string z)
        {
         this.b = x;
         this.c = y;
         this.d = z;
         printf(__FUNCTION__);
        }
        
      ~A()  // 析构函数,用于类的实例销毁时调用
        {
         printf(__FUNCTION__);
        }
  };

对象:

#include <myClass\testClass.mqh>

int OnStart()
  {
   A ac(10, 0.1, "ok");
   Print(ac.b, ac.c, ac.d);

   return(1);
  }

4、类的封装

在 MQL5 中,public、private 和 protected 是 访问控制符,它们用于控制类的成员的访问权限。

public:成员可以被类的外部代码、类的内部代码以及派生类访问。
private:成员只能在类内部的成员函数中访问,外部代码或派生类不能直接访问。
protected:成员既可以在当前类的成员函数中访问,也可以在派生类的成员函数中访问,但不能在外部直接访问。

类:

class A
  {
   private:
      // 声明成员变量
      int b;
      double c;
      string d;
      
      // 声明成员函数
      int add(int x, int y)
        {
         printf(__FUNCTION__);   // 预定义宏,返回函数名称
         return(x+y);
        }
   public:
      A(int x, double y, string z)
        {
         this.b = x;
         this.c = y;
         this.d = z;
         printf(__FUNCTION__);
        }
        
      ~A()  // 析构函数,用于类的实例销毁时调用
        {
         printf(__FUNCTION__);
        }
  };

对象:

#include <myClass\testClass.mqh>

int OnStart()
  {

   
   A ac(10, 0.1, "ok");
   Print(ac.b, ac.c, ac.d); // 会报错

   return(1);
  }

5、类的函数重载

根据传入实参函数种类及个数的不同,选择不同的成员函数。

类:

class A
  {
   private:
      // 声明成员变量
      int b;
      double c;
      string d;
      
      // 声明成员函数
      int add(int x, int y)
        {
         return(x+y);
        }
   public:
      A(int x, double y, string z)
        {
         b = x;
         this.c = y;
         this.d = z;
         Print(this.b);
        }
      A()   // 函数重载
        {
        }
        
      ~A()  // 析构函数,用于类的实例销毁时调用
        {
        }
  };

对象:

#include <myClass\testClass.mqh>

int OnStart()
  {
   A ac(10, 0.1, "ok");
   A ac2;   // 实例化时,会调用第二个构造函数
   A ac3[4];   // 无参数的构造函数,对应的对象可以组成数组

   return(1);
  }

6、类的成员函数提前声明

类的成员函数的声明和定义可以不同时。

类:

class A
  {
   public:
      // 声明成员变量
      int b;
      double c;
      string d;
      
      // 声明成员函数
      int add(int x, int y);
        
      A()   // 构造函数
        {
        }
        
      ~A()  // 析构函数,用于类的实例销毁时调用
        {
        }
  };
  
int A::add(int x, int y)
  {
   return(x+y);
  }

对象:

#include <myClass\testClass.mqh>

int OnStart()
  {
   A ac;
   int x=ac.add(3,20);
   Print(x);

   return(1);
  }

7、const类型变量和函数

class A
  {
   public:
      // 声明成员变量
      int b;
      double c;
      string d;
      
      // 声明成员函数
      int add(const int x, int y)
        {
         x=5;  // 报错,因为const修饰的是常变量,在函数内不能修改
         return(x+y);
        }
        
      A()   // 构造函数
        {
        }
        
      ~A()  // 析构函数,用于类的实例销毁时调用
        {
        }
  };

class A
  {
   public:
      // 声明成员变量
      int b;
      double c;
      string d;
      
      // 声明成员函数
      int add(int x, int y) const
        {
         this.b = 5; // 报错,因为const类型函数不能修改成员变量。
         return(x+y);
        }
        
      A()   // 构造函数
        {
        }
        
      ~A()  // 析构函数,用于类的实例销毁时调用
        {
        }
  };

8、类的静态成员函数

#include <myClass\testClass.mqh>

int OnStart()
  {
   A ac;
   int x = ac.add(3,20);
   int y = A::add(4,5); // 静态成员函数可以不创建对象,直接访问
   // :: 是用于访问类成员的运算符。
   Print(x);
   Print(y);

   return(1);
  }

9、类的静态成员变量

静态成员变量属于类本身,不属于某个实例(对象)。所有对象共享一个静态变量。

静态成员变量的初始化必须在类外部进行。

类:

class A
  {
   public:
      // 声明成员变量
      static int b;  // 声明静态成员变量
      double c;
      string d;
      
      // 声明成员函数
      int add(int x, int y)
        {
         return(x+y);
        }
        
      A()   // 构造函数
        {
        }
        
      ~A()  // 析构函数,用于类的实例销毁时调用
        {
        }
  };
  
int A::b = 10; // 初始化静态成员变量

对象:

#include <myClass\testClass.mqh>

int OnStart()
  {
   Print(A::b);

   return(1);
  }

10、类的继承

子类继承父类后,会继承它的成员函数和成员变量(访问权限允许的成员)。

(1)公有继承

ParentClass.mqh:

class Parent
  {
   private:
      void parentPrivate()
        {
         printf("parentPrivate!");
        }
   
   protected:
      int parProtected;
      void parentProtected()
        {
         printf("parentProtected!");
        }
  
   public:
      void parentPublic()
        {
         printf("parentPublic!");
        }
        
      Parent()   // 构造函数
        {
        }
        
      ~Parent()  // 析构函数
        {
        }
  };

SonClass.mqh:

#include <myclass/ParentClass.mqh>

class Son:public Parent // 公有继承
  {
   public:
      void call_parentPublic()
        {
         parentPublic();
        }

      void call_parentProtected()
        {
         parentProtected();
        }
      /*  报错
      void call_parentPrivate()
        {
         parentPrivate();
        }
      */
      
      void func()
        {
         Parent::parProtected=10;   // 子类可以调用父类的保护成员变量
         Print(parProtected);
        }
  };

脚本:

#include <myClass\sonClass.mqh>

int OnStart()
  {
   Son obj;
   obj.call_parentPublic();
   obj.parentPublic();  // 可以直接调用父类的成员
   obj.call_parentProtected();
   // obj.parentProtected(); // 报错,子类继承父类的保护成员,还是保护成员,所以对象不能调用。

   return(1);
  }

(2)私有继承

ParentClass.mqh:

class Parent
  {
   private:
      void parentPrivate()
        {
         printf("parentPrivate!");
        }
   
   protected:
      void parentProtected()
        {
         printf("parentProtected!");
        }
  
   public:
      void parentPublic()
        {
         printf("parentPublic!");
        }
        
      Parent()   // 构造函数
        {
        }
        
      ~Parent()  // 析构函数
        {
        }
  };

SonClass.mqh:

#include <myclass/ParentClass.mqh>

class Son:private Parent // 私有继承
  {
   public:
      void call_parentPublic()
        {
         parentPublic();
        }

      void call_parentProtected()
        {
         parentProtected();
        }
      /*  //报错
      void call_parentPrivate()
        {
         parentPrivate();
        }
      */
  };

脚本:

#include <myClass\sonClass.mqh>

int OnStart()
  {
   Son obj;
   obj.call_parentPublic();
   // obj.parentPublic();  // 报错,子类继承父类的公有成员是私有成员,对象不能直接访问
   obj.call_parentProtected();
   // obj.parentProtected(); // 报错,子类继承父类的保护成员是私有成员,对象不能直接访问

   return(1);
  }

(3)保护继承

ParentClass.mqh:

class Parent
  {
   private:
      void parentPrivate()
        {
         printf("parentPrivate!");
        }
   
   protected:
      void parentProtected()
        {
         printf("parentProtected!");
        }
  
   public:
      void parentPublic()
        {
         printf("parentPublic!");
        }
        
      Parent()   // 构造函数
        {
        }
        
      ~Parent()  // 析构函数
        {
        }
  };

SonClass.mqh:

#include <myclass/ParentClass.mqh>

class Son:protected Parent // 保护继承
  {
   public:
      void call_parentPublic()
        {
         parentPublic();
        }

      void call_parentProtected()
        {
         parentProtected();
        }
      /*  //报错
      void call_parentPrivate()
        {
         parentPrivate();
        }
      */
  };

脚本:

#include <myClass\sonClass.mqh>

int OnStart()
  {
   Son obj;
   obj.call_parentPublic();
   // obj.parentPublic();  // 报错,子类继承父类的公有成员是保护成员,对象不能直接访问
   obj.call_parentProtected();
   // obj.parentProtected(); // 报错,子类继承父类的保护成员是保护成员,对象不能直接访问

   return(1);
  }

(4)三种继承方式总结

子类的继承方式对父类成员访问权限的影响:

继承方式父类 公有成员父类 保护成员父类 私有成员
公有继承公有保护无法访问
私有继承私有私有无法访问
保护继承保护保护无法访问

(5)子类创建与销毁对象的执行顺序

创建实例的执行顺序为:
  1、执行到类Son构造函数开始(并未执行其函数内部代码)。
  2、执行类Parent的构造函数。
  3、执行类Son构造函数内部代码。

销毁实例的执行顺序为:
  1、执行类Son析构函数内部代码。
  2、执行类Parent析构函数。
  3、返回到类Son析构函数结尾。


ParentClass.mqh:

class Parent
  {
   public:
      Parent()   // 构造函数
        {
         printf(__FUNCTION__);
        }
        
      ~Parent()  // 析构函数
        {
         printf(__FUNCTION__);
        }
  };

sonClass.mqh:

#include <myclass/ParentClass.mqh>

class Son:public Parent
  {
   public:
      Son()   // 构造函数
        {
         printf(__FUNCTION__);
        }
        
      ~Son()  // 析构函数
        {
         printf(__FUNCTION__);
        }
  };

脚本:

#include <myClass\sonClass.mqh>

int OnStart()
  {
   Son obj;

   return(1);
  }

(6)成员初始化列表

ParentClass.mqh

class Parent
  {
   public:
      Parent(int a)   // 构造函数
        {
         Print(a);
        }
        
      ~Parent()  // 析构函数
        {
        }
  };

sonClass.mqh

#include <myclass/ParentClass.mqh>

class Son:public Parent // 公有继承
  {
   public:
      // 语法 构造函数:成员初始化列表
      // 成员初始化列表会在子类构造函数的函数体执行之前,先执行
      // 成员初始化列表如果不显示调用父类构造函数,会默认执行Parent()
      Son(int b):Parent(b)
        {
        }
      
      ~Son()
        {
        }
  };

脚本

#include <myClass\sonClass.mqh>

int OnStart()
  {
   Son obj(5);

   return(1);
  }

(7)函数的重载与重写

函数重载: 指的是在同一个类或父子类中 定义多个函数,它们具有相同的函数名,但参数列表不同(参数个数、类型或顺序不同)。函数的返回类型不影响重载,因为重载是基于参数列表来区分的。

函数重写: 是指 子类重新定义 从父类继承来的函数,以提供特定的实现。重写的函数必须具有 相同的函数签名(包括名称、参数类型、返回类型)。

注:无论是函数的重载还是重写,都优先找子类。在子类的成员函数能找到相应的函数,即函数名和参数列表都能对上,就不再去找父类。如果对不上,才去找父类。

11、类的多态与虚函数、纯虚函数、抽象类

ParentClass.mqh

class Parent
  {
   public:
      // 关键字 virtual 会使函数编程虚函数。
      // 如果不加关键字 virtual,脚本执行obj.func();语句,会执行父类的方法,而不执行子类的方法。
      // 如果加关键字 virtual,脚本执行obj.func();语句,会执行子类的方法,而不执行父类的方法。
      virtual void func()
        {
         printf(__FUNCTION__);
        }
      
      Parent()   // 构造函数
        {
        }
        
      ~Parent()  // 析构函数
        {
        }
  };

sonClass.mqh

#include <myclass/ParentClass.mqh>

class Son:public Parent // 公有继承
  {
   public:
      // override 修饰符表示声明的函数必须为重写父类的虚函数,否则会报错。
      // override可以不写,直接写重写的函数,不过建议写。
      // 如果不重写func()函数,那么脚本执行obj.func();时,会调用父类的func()函数。
      void func() override
        {
         printf(__FUNCTION__);
        }
   
      Son()
        {
        }
      
      ~Son()
        {
        }
  };

脚本

#include <myClass\sonClass.mqh>

int OnStart()
  {
   Parent *obj = new Son();   // 多态
   obj.func();
   return(1);
  }

抽象类是包含至少一个纯虚函数的类。
抽象类不能直接实例化。
抽象类的子类如果不重写抽象类,子类实例化时会报错。

class Parent	// 抽象类
  {
   public:
      virtual void func()=0;  // 定义纯虚函数
      
      Parent()   // 构造函数
        {
        }
        
      ~Parent()  // 析构函数
        {
        }
  };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值