使用类实例化一个对象的时候,构造器会自动执行。构造器用于对象内部变量的初始化。
如果不显式声明构造器,系统会自动创建一个默认的构造器初始化变量。这个默认的构造器并不可见。
在上一章中声明的 CIndicator 类中,我们手动创建了构造器,名字依然是 CIndicator()。也就是说,我们的构造器必须与类名相同。
构造器无需指定返回类型。返回类型始终是void。且访问级别是public。
精简的CIndicator构造器如下:
class CIndicator
{
public:
CIndicator();
// ...
};
下面例子中,我们显式声明构造器,作用仅仅是将main[]数组作为序列值存储。
CIndicator::CIndicator(void)
{
ArraySetAsSeries(main,true);
}
请记住,不需要构造器,就无需创建,系统都为我们准备好了。
利用构造器,还可以做一些复杂的事情,比如参数化其他构造器,初始化众多列表。有了构造器,也就有对应的析构器。当对象销毁的时候调用。更多应用您可以在MQL5参考手册内阅读查看。
面向对象还有一个非常有用的特性就是继承。面向兑现公众,我们可以使用一个类作为模板,创建另一个类。继承类会继承父类的所有方法与属性。(当然,private声明的属性和方法除外,不允许继承)。我们可以在继承类内添加方法,和属性。
我们举例说明这种继承关系和特性。
class CiMA : public CIndicator
{
public:
int Init(string pSymbol,ENUM_TIMEFRAMES pTimeframe, int pMAPeriod,
int pMAShift,ENUM_MA_METHOD pMAMethod, ENUM_APPLIED_PRICE pMAPrice);
};
CiMA类继承了CIndicator类,并声明了新的方法,Init(), pMAShift()。
public方法声明此两个方法,是公开可访问,并可被继承的。
下面我们实现Init方法:
int CiMA::Init(string pSymbol, ENUM_TIMEFRAMES pTimeframe, int pMAPeriod,
int pMAShift, ENUM_MA_METHOD pMAMethod, ENUM_APPLIED_PRICE pMAPrice)
{
handle = iMA(pSymbol,pTimeframe,pMAPeriod,pMAShift,pMAMethod,pMAPrice);
return(handle);
}
Init方法所接收参数较多,注意参数的数据类型。方法返回值是int型。
有时,我们需要在继承类中修改一个方法,或者想要在傅雷中定义方法,但是又担心影响到继承类的接口。这时,我们需要“虚拟方法”。
以Car为例。Class Car有一个方法,ChangGear()。然而,ShiftGear实现过程中,有手动方式和自动方式,实现方法完全不同。这时我们可以将ShiftGear()声明为虚拟方法。然后,实现的细节,在继承类内具体写。就很好地解决了这个问题。
举例说明:
class Car
{
public:
virtual int ShiftGears(int gear) { return(gear); }
};
一定记得,virtual关键字。
下面是具体的,在继承类中的ShiftGear()实现:
class ManualCar : public Car
{
public:
int ShiftGears(int gear);
};
大家看到了,重写ShiftGear方法,变得很简单。接收的参数和返回值,必须与父类相同,且方法名也完全一致。
如果继承类中有方法名与父类完全相同,那么父类的该方法会被覆盖。这种在集成类内重写父类方法的特性,称为“多态”!
还是拿上面的CiMA类举例。我们修改一下,将CIndicator的Init接口声明为虚拟类,并在继承类内实现。
class CIndicator
{
protected:
int handle;
public:
virtual int Init() { return(handle); }
};
那么,都不用修改CiMA,其已经可以使用Init方法。而如果是已写好的类,那么也不用变动,因为方法名相同,自动覆盖。
上面我们定义了一个移动平均值指示器CiMA。下面,我们创建一些该类的实例对象。
CiMA objMa;
执行实例化对象时,类的构造器自动执行。CiMA继承自CIndicator,那么CIndicator的构造器,也会被CiMA继承。objMa是CiMA的实例,实例化的时候自动执行CiMA->CIndicator->Constrator,就是这样一个过程。也就是下面这段:
CIndicator::CIndicator(void)
{
ArraySetAsSeries(main,true);
}
对象一旦创建,我们就可以访问其公共成员。使用点(.)操作符。首先,我们调用该指示器的初始化方法:
objMa.Init(_Symbol, 0, MAPeriod, 0, MAMethod, MAPrice);
看上述代码,Init方法是在CiMA内实现,调用iMA方法返回移动平均值,并赋值给CiMA的保护变量handle。
我们还声明了一个保护属性main[],存储指示器数据。保护属性不可访问,使用公有方法Main()进行操作。
Print(objMa.Main())
如果有需要,我们在程序内还可以创建许许多多对象。只要实例化的时候,使用不同的名字就可以了。这种面相对象的方法,节省时间,避免了大量重复的代码,使程序看起来更为简洁有效,在处理大量复杂的交易任务时,非常有用。