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删除。对于其他类型的指针,将返回错误。
除了在继承过程中重新定义函数之外,多态性还包括在一个类中实现具有相同名称但参数集不同的函数。这意味着类可能有多个同名但类型和/或参数集不同的函数。在这种情况下,多态性是通过函数重载实现的。