跳至内容

Polymorphism

多态性

多态性是指通过继承关系关联的不同类对象在调用相同函数元素时,能够以多种方式作出响应。它有助于创建一种通用机制,描述不仅是基类的行为,还有派生类的行为。

让我们继续开发基类CShape,并定义一个成员函数GetArea(),用于计算形状的面积。在所有由基类继承产生的派生类中,我们根据计算特定形状面积的规则重新定义这个函数。

对于正方形(类CSquare),面积通过其边长计算;对于圆形(类CCircle),面积通过半径表示等。我们可以创建一个数组来存储CShape类型的对象,其中可以存储基类和所有派生类的对象。然后我们可以调用数组中每个元素的相同函数。

示例:

//--- Base class
class CShape
  {
protected:
   int            m_type;                // Shape type
   int            m_xpos;                // X - coordinate of the base point
   int            m_ypos;                // Y - coordinate of the base point
public:
   void           CShape(){m_type=0;};   // constructor, type=0
   int            GetType(){return(m_type);};// returns type of the shape
virtual
   double         GetArea(){return (0); }// returns area of the shape
  };

现在,所有派生类都有一个返回零值的成员函数getArea()。每个派生类中该函数的实现会有所不同。

//--- The derived class Circle
class CCircle : public CShape            // After a colon we define the base class
  {                                      // from which inheritance is made
private:
   double         m_radius;              // circle radius

public:
   void           CCircle(){m_type=1;};  // constructor, type=1
   void           SetRadius(double r){m_radius=r;};
   virtual double GetArea(){return (3.14*m_radius*m_radius);}// circle area
  };

对于正方形类,声明是相同的:

//--- The derived class Square
class CSquare : public CShape            // After a colon we define the base class
  {                                      // from which inheritance is made
private:
   double          m_square_side;        // square side

public:
   void            CSquare(){m_type=2;}; // constructor, type=1
   void            SetSide(double s){m_square_side=s;};
   virtual double  GetArea(){return (m_square_side*m_square_side);}// square area
  };

为了计算正方形和圆形的面积,我们需要相应的m_radius和m_square_side值,因此在相应类的声明中添加了SetRadius()和SetSide()函数。

假设我们的程序中使用的是从基类CShape派生的不同类型对象(CCircle和CSquare)。多态性允许创建基类CShape对象的数组,但在声明这个数组时,这些对象仍然是未知的,其类型也是未定义的。

关于数组中每个元素将包含哪种类型的对象,决定将在程序执行过程中直接做出。这涉及到适当类的对象的动态创建,因此需要使用对象指针而不是对象本身。

new运算符用于动态创建对象。每个这样的对象都必须使用delete运算符单独且明确地删除。因此,我们将声明一个CShape类型的指针数组,并为每个元素创建一个适当类型的对象(new Class_Name),如下例所示:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Declare an array of object pointers of the base type
   CShape *shapes[5];   // An array of pointers to CShape object

//--- Here fill in the array with derived objects
//--- Declare a pointer to the object of CCircle type
   CCircle *circle=new CCircle();
//--- Set object properties at the circle pointer
   circle.SetRadius(2.5);
//--- Place the pointer value in shapes[0]
   shapes[0]=circle;

//--- Create another CCircle object and write down its pointer in shapes[1]
   circle=new CCircle();
   shapes[1]=circle;
   circle.SetRadius(5);

//--- Here we intentionally "forget" to set a value for shapes[2]
//circle=new CCircle();
//circle.SetRadius(10);
//shapes[2]=circle;

//--- Set NULL for the element that is not used
   shapes[2]=NULL;

//--- Create a CSquare object and write down its pointer to shapes[3]
   CSquare *square=new CSquare();
   square.SetSide(5);
   shapes[3]=square;

//--- Create a CSquare object and write down its pointer to shapes[4]
   square=new CSquare();
   square.SetSide(10);
   shapes[4]=square;

//--- We have an array of pointers, get its size
   int total=ArraySize(shapes);
//--- Pass in a loop through all pointers in the array
   for(int i=0; i<5;i++)
     {
      //--- If the pointer at the specified index is valid
      if(CheckPointer(shapes[i])!=POINTER_INVALID)
        {
         //--- Log the type and square of the shape
         PrintFormat("The object of type %d has the square %G",
               shapes[i].GetType(),
               shapes[i].GetArea());
        }
      //--- If the pointer has type POINTER_INVALID
      else
        {
         //--- Notify of an error
         PrintFormat("Object shapes[%d] has not been initialized! Its pointer is %s",
                     i,EnumToString(CheckPointer(shapes[i])));
        }
     }

//--- We must delete all created dynamic objects
   for(int i=0;i<total;i++)
     {
      //--- We can delete only the objects with pointers of POINTER_DYNAMIC type
      if(CheckPointer(shapes[i])==POINTER_DYNAMIC)
        {
         //--- Notify of deletion
         PrintFormat("Deleting shapes[%d]",i);
         //--- Delete an object by its pointer
         delete shapes[i];
        }
     }
  }

请注意,当使用delete运算符删除对象时,必须检查其指针的类型。只有具有POINTER_DYNAMIC指针的对象才能使用delete删除。对于其他类型的指针,将返回错误。

除了在继承过程中重新定义函数之外,多态性还包括在一个类中实现具有相同名称但参数集不同的函数。这意味着类可能有多个同名但类型和/或参数集不同的函数。在这种情况下,多态性是通过函数重载实现的。

最后更新于