PLOです。アプリケーションの問題 - ページ 8

 
Interesting:

1.子孫機能は使用できません。誰がどのようにしたのかわかりませんが、個人的にはArrayからSetRadius()とSetSide()にアクセスしたことがありません。もしかしたら、autogenousで解決する方法があるかもしれませんが、私はそれをせずにやりたいと思っています。

2.ポインターの扱いを間違えているのかもしれませんが、ずっと漏れがあるか、メインの作業が行われるブロックの中ですぐにポインターを打たないといけないんです。

すべての利用可能な...前略
 
equivalent23:

例を挙げてみましょうか。

ただ、私が挙げた例はドキュメントから引用したもので、どのように動作するべきか明確ではありませんが......。

このような仕組みになっています。しかし、完全にドキュメントから外れている :/ (しかし、もう一度、ポインタで練習しました)

#property copyright "Ya"
#property link      "Ya"
#property version   "1.00"
//--- Базовый класс
class CShape
  {
protected:
   int               m_type;                // тип фигуры
   int               m_xpos;                // X - координата точки привязки
   int               m_ypos;                // Y - координата точки привязки
public:
   void           CShape(){m_type=0;};   // конструктор, тип равен нулю
   int            GetType(){return(m_type);};// возвращает тип фигуры
   virtual void           SetRadius(double r){return;};
   virtual void           SetSide(double s){return;};
   virtual double         GetArea(){return(0); }// возвращает площадь фигуры
  };
//--- производный класс Круг
class CCircle: public CShape          // после двоеточия указывается базовый класс,
  {                                      // от которого производится наследование 
private:
   double            m_radius;              // радиус круга

public:
   void           CCircle(){m_type=1; m_radius=10;};  // конструктор, тип равен 1 
   virtual void           SetRadius(double r){m_radius=r;};
   virtual double GetArea(){return(3.14*m_radius*m_radius);}// площадь круга
  };
//--- производный класс Квадрат
class CSquare: public CShape          // после двоеточия указывается базовый класс,
  {                                      // от которого производится наследование 
private:
   double            m_square_side;        // сторона квадрата

public:
   void            CSquare(){m_type=2;}; // конструктор, тип равен 2 
   virtual void            SetSide(double s){m_square_side=s;};
   virtual double GetArea(){return(m_square_side*m_square_side);}//площадь квадрата
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   CCircle *ci=new CCircle;
   CSquare *sq=new CSquare;
   CShape  *shapes[2];                       // массив объектов CShape

   shapes[0]=ci;
   shapes[1]=sq;
////---зададим уникальные свойства объектов
   shapes[0].SetRadius(5.0);
   shapes[1].SetSide(4.0);
   for(int i=0; i<2;i++)
     {
      //--- тип и площадь фигуры
      Print("Объект типа "+shapes[i].GetType()+" имеет площадь "+shapes[i].GetArea());
     }
 
AlexSTAL:

実行する。

は、もっとシンプルにできるはず...。仮想化


そういうことではないんです。単にポインターを使う という話ではなく、このポインターをベースクラスの型にして配列にするという話です。

CShape ArrShapes[10]; // массив объектов CShape

単純な配列でもポインターの配列でも、ベースクラスに書かれているものだけが動作し、利用できるのです。

それとも何か見落としているのでしょうか。

例えば、ベースクラス(構造体として設計されている)を少し修正した場合

//class CShape
struct CShape
//Базовый класс
{  
protected: 
int            m_type;                // тип фигуры
int            m_xpos;                // X - координата точки привязки
int            m_ypos;                // Y - координата точки привязки

public:
void           CShape(){m_type=0;};   // конструктор, тип равен нулю
int            GetType(){return(m_type);};// возвращает тип фигуры

void           SetPosX(int s){m_xpos=s;};
int            GetPosX(){return(m_xpos);};

void           SetPosY(int s){m_ypos=s;};
int            GetPosY(){return(m_ypos);};

double GetArea(){return (0); }// возвращает площадь фигуры

};

これを全部配列に詰め込めば、少なくともベースクラスで宣言されている機能にはアクセスできるようになる。

問題は、配列がベースクラス型(つまり、配列がCShape型)である場合に、どのように子孫の機能にアクセスするかということです。

Когда нужно использовать указатели в MQL5
Когда нужно использовать указатели в MQL5
  • 2010.03.25
  • MetaQuotes Software Corp.
  • www.mql5.com
Все объекты в MQL5 по умолчанию передаются по ссылке, но есть возможность использовать и указатели объектов. При этом есть опасность получить в качестве параметра функции указатель неинициализированного объекта. В этом случае работа программы будет завершена критически с последующей выгрузкой. Автоматически создаваемые объекты как правило такой ошибки не вызывают, и в этом отношении они достаточно безопасны. В этой статье мы попробуем разобраться в чем разница между ссылкой и указателей, когда оправдано использование указателей и как написать безопасный код с использованием указателей.
 
Interesting:

ということではありません。単純にポインターを使う のではなく、このポインターをベースクラスの型にして配列にするという話です。

問題は、配列がベースクラス型(つまりCShape型)である場合に、子孫からどのように機能にアクセスするかということです。

最後のページには、その方法を書きました。

class CBase
  {
public:
   void m_radius() {Print("CBase");}
  };

class CTest : public CBase
  {
public:
   void m_radius() {Print("CTest");}
  };

CBase* Base;

void OnStart()
  {
   Base = new CTest;
   Base.m_radius();
   ((CTest *)Base).m_radius();
   delete Base;
  }
 

同じコードで、配列だけです。

class CBase
  {
public:
   void m_radius() {Print("CBase");}
  };

class CTest : public CBase
  {
public:
   void m_radius() {Print("CTest");}
  };

CBase* Base[1];

void OnStart()
  {
   Base[0] = new CTest;
   Base[0].m_radius();
   ((CTest *)Base[0]).m_radius();
   delete Base[0];
  }
 
Yedelkin:

そういうことなんです。しかし、完全にドキュメントから外れている :/)

まあ、同じ意味で、少なくともベースクラスですべての関数を指定する必要があります(そうしないとアクセスできません)。
 
AlexSTAL:

実行する。

このようなものに。

((CTest *)Base).m_radius();

はキーボードの没収と一緒に引き剥がすべき。

C++では、dynamic_castでクラス階層を移動することができますが、これも好まれません。MQLの場合、バグが全く別の場所にあるため、簡単に解決できない暗黙のクラッシュが発生することがあります。

したがって、このタイプの変換を使用することは強くお勧めします。つまり、まったくです。ご先祖様にお願いします、子供たちにニ。

 
TheXpert:

このようなものに。

手を離し、キーボードを没収してください。

C++では、dynamic_castを使ってクラス階層を移動することができますが、そこでも嫌われています。MQLでは、バグが全く別の場所にあるため、簡単に解決できない暗黙のクラッシュが発生することがあります。

したがって、このような変換を行うことは絶対に避けてください。つまり、全然ダメなんです。子供ではなく、ご先祖様にお願いします。

なんて答えるのが丁寧なんだろう...。

プログラマがあまりに馬鹿だと、単純な1+1の操作で暗黙のうちにクラッシュしてしまうことも......。

そして、MQL5はC++ではないことを指摘したい...。

これはあくまで可能性であって、応用の問題ではないのですが......。

 
AlexSTAL:

同じコードで、配列だけです。


1.m_radius()を先祖から削除、例にはない。:)また、OnStart()では、これを使っての作業はありません。

2.他にdelete Base[0]の行を入れる場所はないのでしょうか?例えば、スクリプトではなくフクロウで、それでも配列のデータが必要な場合。

すぐにメモリーリークが発生しました。そのためにストラクチャーに乗り換えることになったのですが...。

 
Interesting:

1.m_radius() を削除、この例には存在しない。そして、OnStart()の中で、それを使って仕事をすることはありません。

2. delete Base[0]の行を別の場所に移動してもよいですか?例えば、スクリプトではなくフクロウで、それでも配列のデータが必要な場合。

すぐにメモリリークが発生しました。そのためにストラクチャーに乗り換えることになったのですが...。

1) 取り外すと、動作します。

class CBase
  {
public:
  };

class CTest : public CBase
  {
public:
   void m_radius() {Print("CTest");}
  };

CBase* Base[1];

void OnStart()
  {
   Base[0] = new CTest;
   ((CTest *)Base[0]).m_radius();
   delete Base[0];
  }
2) プログラムが終了する前に削除することが主...しかし、このポインタを関数内で作成した場合、グローバルな場所に保存するように配慮する必要がある...。