多态性

多态性为不同分类对象提供了一个机会,通过继承,当调用相同函数元素时以不同的方式回应,通过帮助创造普遍原理表述行为不仅是基础类别,更是继承类别。

继续研发基础分类CShape,定义成员函数GetArea(), 目的在于计算阴影区域,在所有继承分类里,通过从基础分类继承下来,我们重新定义这种函数以计算特殊阴影面积的规则相同

在一个区域内(CSquare分类),通过面积计算一圈(CCircle分类),区域通过半径等表示。创建数组存储CShape类型交易对象,基础类别中的量个交易品种和继承的交易分类都能存储,然后就可以调用数组中每个元素的任意相同函数。

示例:

//--- 基本类
class CShape
  {
protected
   int            m_type;                // 形状类型
   int            m_xpos;                // 基本点的X - 坐标
   int            m_ypos;                // 基本点的Y - 坐标
public:
   void           CShape(){m_type=0;};   // 构造函数, 类型=0
   int            GetType(){return(m_type);};// 返回 图形类型
virtual
   double         GetArea(){return (0); }// 返回 图形区域
  };

现在,所有的派生类都有成员函数 getArea(), 返回0值,该函数以每个后代变化转变为基础实现。

//--- 派生类 圆形
class CCircle : public CShape            // 冒号后定义基本类
  {                                      // 从继承算法开始
private:
   int            m_radius;              // 圆弧半径
 
public:
   void           CCircle(){m_type=1;};  // 构造函数, 类型=1
   void           SetRadius(double r){m_radius=r;};
   virtual double GetArea(){return (3.14*m_radius*m_radius);}// 圆形 区域
  };

对于Square分类来说,申报是相同的:

//--- 派生类 方形
class CSquare : public CShape            // 冒号后定义基本类
  {                                      // 从继承算法开始
private:
   int             m_square_side;        // 方形的边
 
public:
   void            CSquare(){m_type=2;}; // 构造函数, 类型=1
   void            SetSide(double s){m_square_side=s;};
   virtual double GetArea(){return (m_square_side*m_square_side);}// 方形区域
  };

为了计算圆圈面积,需要类似m_radius 和 m_square_side类型值,因此在类似分类中添加SetRadius 和 SetSide()

假设从一个基本类型CShape衍生的不同类型 (CCircle和CSquare) 的对象用在我们的程序。多态性允许创建基类CShape对象的数组,但是当声明该数组时,则这些对象身份不明且它们的类型也不明确。

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

new操作符用于动态创建对象。每个这样的对象都必须独立且明确地使用delete操作符删除。所以,我们将声明CShape类型的指针数组,并为每个元素(new Class_Name)创建合适类型的对象,如下面的脚本示例所示:

//+------------------------------------------------------------------+
//| 脚本程序开始函数                                                   |
//+------------------------------------------------------------------+
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<total;i++)
     {
      //--- 我们只可以删除POINTER_DYNAMIC类型指针的对象
      if(CheckPointer(shapes[i])==POINTER_DYNAMIC)
        {
         //--- 删除的通知
         PrintFormat("Deleting shapes[%d]",i);
         //--- 通过指针删除对象 
         delete shapes[i];
        }
     }
  }

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

但此外,通过继承和多态性重新定义函数,包括一个工具和一个分离中建立的相同函数的不同参量,这表示该分类拥有几个相同名称的函数,但是不同类型的参量,因此,通过function overload实施多态性。

另见

标准程序库