文章 "在 MQL5 中使用对象指针" - 页 3

 
在这种情况下不要使用指针。
 
Barbarian2:

我仍然不理解 MQL5 和 MQL4 中的指针和引用。除了额外的代码,引用传递和指针传递有什么区别?在 C++ 中是有区别的,但在这里有什么区别呢?如果不难写得更详细些。

引用传递要求对引用传递的对象进行初始化。而通过指针传递则没有这种限制:

class CShape
{
   public:
      string name;
};

void OnInit()
{
   CShape* shape = NULL; 
   TestShapePointer(shape);
   //Critical Error!
   TestShapeRef(shape);
   
}

void TestShapeRef(CShape& shape)
{
   printf(shape.name);
}

void TestShapePointer(CShape* shape)
{
   if(CheckPointer(shape) != POINTER_INVALID)
      printf(shape.name);
}

调用 TestShapeRef函数 时,代码会因为形状未初始化而崩溃。另一方面,在 TestShapePointer 函数中,需要不断检查传递的对象是否初始化。因此,请遵循轻率原则:

如果必须保证对象在传递给函数时已经存在,则使用"&"传递。如果函数需要一个状态未定义的对象,则使用 "*"指针传递,并在函数内部检查传递指针的有效性。

还有一个细微的差别需要注意。请看前面的例子:

class CShape
{
   public:
      string name;
};

void OnInit()
{
   CShape* shape = NULL; 
   TestShapePointer(shape);
   printf(shape.name); //ERROR (!?)
}

void TestShapePointer(CShape* shape)
{
   if(CheckPointer(shape) == POINTER_INVALID)
      shape = new CShape();
   printf(shape.name);
}
这个程序能正常运行吗?不会,它将在printf(shape.name); //ERROR (!?) 行以 "无效指针访问 "错误结束,尽管我们似乎可以保证在 TestShapePointer 函数中创建一个对象。问题的关键在于,实际上传递的是一个 NULL 引用,而不是 shape。也就是说,函数内部的形状和传递的形状是不同的 对象!因此,在退出函数后,shape 仍然等于 NULL,而函数内部的形状指针则丢失了(在堆栈中被清除)。所以
 

可以用不同类型的对象创建一个数组吗?

让我们举这个例子:

//+------------------------------------------------------------------+
//|#Test.mq5
//| 2014 年 MetaQuotes 软件公司版权所有。
//|http://www.mql5.com | |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//---
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//---
CChartObjectRectLabel rect_label;
CChartObjectButton    button;
CChartObjectEdit      edit;
//---
CChartObject *objects[];
//+------------------------------------------------------------------+
//| 脚本程序启动功能|
//+------------------------------------------------------------------+
void OnStart()
  {
   edit.Create(0,"edit_1",0,20,20,100,20);
   button.Create(0,"button_1",0,20,40,100,20);
   rect_label.Create(0,"rect_label_1",0,20,60,100,20);
//---
   AddObjectToArray(edit);
   AddObjectToArray(button);
   AddObjectToArray(rect_label);
//---
   //objects[0].// 如何访问 CChartObjectEdit 类的方法?
   //objects[1].// 如何访问 CChartObjectButton 类的方法?
   //objects[2].// 如何访问 CChartObjectRectLabel 类的方法?
//---
   while(!IsStopped()) Sleep(1000);
  }
//+------------------------------------------------------------------+
//| 返回对象的数量|
//+------------------------------------------------------------------+
int ElementsTotal()
  {
   return(ArraySize(objects));
  }
//+------------------------------------------------------------------+
//|| 向数组添加一个对象|
//+------------------------------------------------------------------+
void AddObjectToArray(CChartObject &object)
  {
   int size=ElementsTotal();
//---
   ArrayResize(objects,size+1);
   objects[size]=GetPointer(object);
//---
   if(CheckPointer(objects[size])!=POINTER_INVALID)
      Print(__FUNCSIG__," >>> array["+IntegerToString(size)+"]: ",objects[size].Name(),
            "; object type: ",ObjectTypeToString(objects[size].Type()));
  }
//+------------------------------------------------------------------+
//| 将对象类型转换为字符串|
//+------------------------------------------------------------------+
string ObjectTypeToString(int type)
  {
   string str="";
//---
   switch((ENUM_OBJECT)type)
     {
      case OBJ_EDIT            : return("edit");            break;
      case OBJ_BUTTON          : return("button");          break;
      case OBJ_RECTANGLE_LABEL : return("rectangle label"); break;
     }
//---
   return("undefined object type");
  }
//+------------------------------------------------------------------+

//---

如何访问 继承类的方法

 
tol64:

如何访问 继承类的方法

您是否尝试过向目标类型转换?
 
Rosh:
你试过施放目标类型吗?
没有,第一次听说。我在哪里可以读到?
 
tol64:
没有,我还是第一次听说。我在哪里可以读到?
这是一个常见的形容词类型,这里有一个例子:

//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CFoo
  {
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CBar : public CFoo
  {
public:
   void func(int x) { Print("Hello from Bar ",x); }
  };
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void func(CFoo *foo)
  {
//--- 直接从指针到基本类型的转换调用
   ((CBar*)foo).func(1);
//--- 调用时转换为目标类型,并以所需类型保存指针副本
   CBar *b=(CBar *)foo;
   b.func(2);
//--- 删除动态创建的类
   delete foo;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnStart()
  {
   func(new CBar);
  }
//+------------------------------------------------------------------+
 
mql5:
通常的类型转换,这里有一个例子:

谢谢。我会研究一下的。
 
Rosh:
你试过向目标类型施法吗?
妈的,然后你就开始谈论语言安全了?
 
TheXpert:
妈的,这之后你还谈语言安全?
你找到安全漏洞了吗?)
 

使用多态性 不是更好吗?

是这样的

CChartObject *ptr_rect_label;
CChartObject *ptr_button;
CChartObject *ptr_edit;
CChartObject *objects[];
//---
ptr_rect_label=new CChartObjectRectLabel;
ptr_button=new CChartObjectButton;
ptr_edit=new CChartObjectEdit;