//--- Example for receiving class//---class CAnyClass : public CAnyBaseClass // of course CAnyBaseClass inherits from CObject in the end too
{
private:
CWhatEver m_object; // embedded object
CFurther m_further; // embedded object
public:
//+------------------------------------------------------------------+//| Creation |//+------------------------------------------------------------------+
CAnyClass(void)
{
m_classname="CAnyClass"; //--- Connect side chains
m_object.CustomEventReceiver(PTR(this));
m_further.CustomEventReceiver(PTR(this));
}
protected:
//+------------------------------------------------------------------+//| Custom event handler for side chain messages |//+------------------------------------------------------------------+virtualvoid OnCustomEvent(CObject * sender, int eventid)
{
if (sender==PTR(m_object))
{
switch (eventid)
{
case123456:
Print("Here we go with 123456");
break;
//...
}
}
elseif (sender==PTR(m_further))
{
//...
}
}
};
これは構造体プログラミングであり、OOPではないので、完全に間違っているとは言えません。大きな違いは、継承とオーバーロードの力です。ところで、実際のグラフィカル・オブジェクトを継承することはできませんが、あらゆるものをコード・オブジェクトとして表現し、そのオブジェクトから線などを参照することは可能です。これはMFCやMQLのクラスでも同じです。
もし行がオブジェクトなら、そのように扱います。外では配列を扱わず、クラスコレクションの中でポインターを扱います。CWndContainerを見て、そのイメージを掴んでください。このクラスは、主にCWndオブジェクトのポインタ配列を管理するコンテナです。もう一歩進んで、あなたの構造はこうなっているはずです。
すべてのオブジェクトのベースとなるCObject
CPriceTimeObjectsは、価格や時間に基づくオブジェクトのベースとなるもので、CObjectから派生したものです。このオブジェクトは作成をコントロールし、時間と価格を保持し、次の継承者が使用できるOnCreate()を呼び出します。また、Tick関数も持っており、仮想のOnTick()を呼び出し、それを継承者がオーバーロードします。
トレンドラインのベースとなるCTrendLineは、CPriceTimeObjectsを継承し、ObjectCreate関数を使って 最終ラインを作成するOnCreateを扱います。また、OnTick()ハンドラを持って、Tickイベントに反応するようにします。
これに加えて、CTimePriceObjectオブジェクトを保持するポインタ配列を管理するコンテナ・クラスがあり、これもCTimePriceObjectを継承してOnTick()をその「子」たちに渡している。コンテナにはOnChartEvent()を処理する関数もあり、線を追加したり削除したりする。また、行が作成された後にエキスパートが追加された場合、既存のオブジェクトをすべてスキャンするスキャン関数も持っている必要があります。さらに、CTimePriceからオーバーロードされたOnTick()を処理し、そこの配列をループし、その中のすべてのCTrendLineオブジェクトに、仮想OnTickによって処理されるすべての子オブジェクトのTick関数を呼び出して反応する責任を感じるかどうかを尋ねます。なぜまたこのようなことをするのでしょうか?CTrendLineはCTimePriceからこの関数をオーバーロードし、このクラスはさらなる関数でさらなる継承者に継承されることが可能だからです。
Dorekさん、とても素晴らしいです。
でも、いくつか疑問があります。
CTimePriceObjectを保持するコンテナは、なぜCTimePriceObjectから自身を継承する必要があるのでしょうか?例えば、標準的なライブラリのCIndicatorはCArrayObjを継承しており、おそらく継承せずにCIndicatorを参照しています。
しかし、ある種のオブジェクトのコンテナは、そのオブジェクト自体を継承するという考え方は、正しいとは思いますが、私には理解できません(コンテナは、それ自身がそれを含むオブジェクトではないので、つまり、「is a」関係がない)。
この点についての見解をお聞かせください。
次に、CTrendLineが言語ネイティブのObjectCreate関数を使って最終行を作成するというのは、標準ライブラリに頼らずにゼロからフレームワークを構築しているように見えますが、どうでしょうか?
例えば、標準ライブラリのすべてのCIndicatorオブジェクトに、直近のXバーで価格が何回バッファに触れたかを表示できるようにしたい場合、標準ライブラリ自体を拡張することをお勧めしますか?
を表示できるようにしたいとします。CIndicatorやCIndicatorBufferのような基底クラスを拡張すると、標準ライブラリのすべての依存オブジェクトが、あなたの
例えばCiMAのようなものです。これらのカスタムインジケータクラスをすべて自分のフォルダにコピーし、それらの継承を新しいCIndicatorBufferに変更しますか? metaquotesがその標準CIndicatorBufferまたは上記のクラスに何かを追加したらどうしますか?
ご教示いただきありがとうございました。
BR
Willbur:
...
このようにすると、私のSmartLineオブジェクトがMT5のメニューに、トレンドライン、矢印、テキストオブジェクトなどの 横に表示されるはずです。
...
MT5がそれを可能にするならば、残りの問題、すなわち、価格が変化したときにターミナル・プログラムによってどのようにオブジェクトをトリガーすることができるかを議論しなければなりません。
...非常に素晴らしい、Dorek。
でも、いくつか疑問があります。
CTimePriceObjectを保持するコンテナは、なぜCTimePriceObjectから自分自身を継承しなければならないのでしょうか?例えば、標準的なライブラリのCIndicatorはCArrayObjを継承しており、おそらくCIndicatorを継承せずに参照しています。
しかし、ある種のオブジェクトのコンテナは、そのオブジェクト自体を継承するという考え方は、正しいとは思いますが、私には理解できません(コンテナは、それ自身がそれを含むオブジェクトではないので、つまり、「is a」関係がない)。
この点についての見解をお聞かせください。
次に、CTrendLineが言語ネイティブのObjectCreate関数を使って最終行を作成するというのは、標準ライブラリに頼らずにゼロからフレームワークを構築しているように見えますが、どうでしょうか?
例えば、標準ライブラリのすべてのCIndicatorオブジェクトに、直近のXバーで価格が何回バッファに触れたかを表示できるようにしたい場合、標準ライブラリ自体を拡張することをいつ推奨しますか?
を表示できるようにしたいとします。CIndicatorやCIndicatorBufferのような基底クラスを拡張すると、標準ライブラリのすべての依存オブジェクトが、あなたの
例えばCiMAのようなものです。これらのカスタムインジケータクラスをすべて自分のフォルダにコピーし、それらの継承を新しいCIndicatorBufferに変更しますか? metaquotesがその標準CIndicatorBufferまたは上記のクラスに何かを追加したらどうしますか?
ご教示いただきありがとうございました。
BR
1.コンテナの継承について。
MQLの制限として、複数の継承をすることができません。そのため、最低でも一回は死ななければなりません。もちろん、CArrayObjを継承することも意味がありますが、私ならそうはしません。なぜなら、コンテナはCTimePriceオブジェクトが処理するすべてのイベント、たとえばTick()->OnTick()を処理して子オブジェクトに分配し、配列オブジェクトはそれとは関係ないからです。同じベースクラスを継承する他のオブジェクトを保持するコンテナ・オブジェクトは、より多くの共通性を持っています。このようなコンテナは、価格や時間に基づいたアンカーを持つこともでき、このようなコンテナを移動したりシフトしたりすると、コンテナはそのすべての「子」も移動させることになります。これはほんの一例ですが、このようなアイデアのリストは、おそらく配列の機能に関するアイデアのリストよりも長いと思います。
そして、このように、多くの種類のオブジェクトを扱うクラスを作成し、その間に得た経験から、この方法で継承を管理することは正しい判断であったと思います。
2.ゼロからのフレームワーク。
こちらも同様です。標準ライブラリにもう少し深く入り込むと、気に入らないものがたくさん出てきました。性能が悪いだけでなく、柔軟性に欠け、また、アーキテクチャが不完全なためです。例えば、グローバルなCMouseクラス/オブジェクトや、CWndとCObjectの間のクラスがありません。CWndオブジェクトは、線と同様にチャートの子であり、そのようなオブジェクトへの接続や、上に書いたようなオブジェクトの最終実装が全くありません。そして、そのようなチャート・オブジェクトをすべて保持し、1つのコマンドですべての表示/非表示を切り替えたり、破棄したりできるような、マスター・オブジェクトも存在しません。CCanvas も同様で、素晴らしいクラスですが、CWnd を継承したビットマップをベースにしたインタラクティブなオブジェクトを作成できる CWnd の実装はどこにあるのでしょうか?などなど。
さらに、すべての標準ライブラリの構造全体がサイドチェインを許さないのですが、これはMQLがボイドポインタを許さないため、必要なことなのです。例えば例えば、私はCDragLineというクラスを使っていて、ドラッグ可能なトレンドラインオブジェクトを作成することができます。そのようなトレンドラインオブジェクトが注文に接続され、さらにパネル/ディスプレイに接続される場合、接続されたパネルが注文の変更によって引き起こされる動き/変化に関する情報を取得できるようなサイドチェーンを使用する可能性が必要です。また、その逆で、注文を移動させるオプションと、ライン自体がドラッグされたときにパネルに通知するオプションが必要です。このような三角形のメッセージングは標準ライブラリ では行えません。これは、サイドチェーンによって行われます。つまり、すべてのオブジェクトは、CObjectの高度なバージョンを継承しているのです。このクラスは、他のオブジェクトをあるオブジェクトに接続し、接続されたオブジェクトにメッセージを送信することができます。こうすることで、より複雑で効果的なメッセージングが、変なコードを書くことなく可能になるのです。
しかし、私は、標準的なライブラリの99%を削除することにしました。オリジナルから残っているクラスは、CCanvas(ただし、いくつかの変更とバグフィックスがあります。
--------------
もし、サイドチェーンの機能に興味がある人がいたら、ここに私のCObjectクラスのコードがあります。Object.mqhの元のCObjectをアップデートのたびに置き換えると、標準ライブラリのほとんどの部分がこのサイドチェイン機能の拡張を受けることができます。ちなみに、オリジナルでは行われていないノード接続も実装されています。
このようなサイドチェーン機能を追加するには、受信側クラスの内部で次のようにします。
送信側クラスのCWhatEverとCFurtherは受信側のこと、つまり受信者がいるかどうかについては何も知らない。コードは以下のようになる。
これがCObjectの置き換えです。
詳しく説明していただき、またサイドチェーンのアイデアを共有していただきありがとうございます。
正直なところ、私はよく理解しておらず、コードはコンパイルできません(アイデアを得るために、あなたが投稿したCObjectを直接継承した空のクラスとしてCWhatEverとCFurtherを作成しました。)
CWhatEver::CWhatEver cannot call private memberfunctionという コンパイルエラーが2つ出て、CFurtherも同じエラーでした。
また、「サイドチェーン」という言葉をググってみましたが、見つかりませんでした。 もし、私が読むことのできる文章をご存知でしたら、とても助かります。
BR
はい、クラスは空です、それがコンパイルできない理由です。これは単なるプレースホルダーです。
サイドチェーンは正式な表現ではないかもしれませんが、ボイドポインタや多重継承に対する私のクリーンなMQLワークアラウンドです。簡単に言うとオブジェクトがクラスに埋め込まれている場合、そのクラスがカスタムイベントの レシーバーであることを「伝える」ことができるので、非常に便利な機能です。このようにすることで、スパゲッティ・コーディングを避けることができます。
例えば、次のようなものがあるとします。
return OnClick();
のように、最後の派生クラスのオーバーロードを最初に呼び出す場合、次のように拡張することができます。
return OnClick()&CustomEvent(CUSTOM_CLICK);
こうすることで、通常は
仮想ブールOnClick()
関数を持つ派生クラスだけでなく、そのオブジェクトを含むクラスもクリック通知を受け取れるようになります。
つまり、メッセージを送る相手のオブジェクトを知る必要がある通常のメッセージングではなく、カスタムイベントを通じて、任意の2つのオブジェクト間で通信する方法ということですか?
その考えは理解できますが、埋め込みオブジェクトというのはどういう意味ですか?あなたのCAnyClassのコードには2つのプライベートオブジェクトがありました。埋め込みというのは、それらのボディがまた、CAnyClassの内部で宣言されなければならないということですか?
CAnyClass の内部で宣言されるべきなのか、それとも外部で定義することができるのでしょうか?つまり、あなたが使っている埋め込みとは、他のオブジェクトの中にあるプライベートなオブジェクトのことですか?
例えば、私がCAnyClassの外側にCWhatEverを書き、あるイベントに関してCAnyClassにメッセージを送りたい場合、CWhatEverの中で私は以下を返すということですか?
return OnClick()&CustomEvent(CUSTOM_CLICK); // <=== &の代わりに&&ということですか?
これは、通常通りCWhatEverの派生クラスと、(カスタムイベントのため)CAnyClassである包含クラスをメッセージするのでしょうか?
そして、なぜCObjectは#ifndefの中で定義されているのでしょうか?
ところで、あなたのCObjectのstdlib.mqhの目的は何でしょうか?
下から上へ...
- stdlibは、オリジナルのobject.mqhに含まれていないのでしょうか?私はここでそれを必要としないが、それは2つのダブルを比較する唯一の信頼できる方法であるCompareDouble()を含んでいます。
- 私は標準では二重定義を避けるために#ifndefを使用し、条件付きコンパイルに使用します
- はい、三角形のメッセージングのために
- バイナリ&と論理バージョン&&はboolの結果で同じです。
- 埋め込みとは、外来クラスのインスタンスやオブジェクトが他のクラスの一部であり、両者が互いに派生していない場合を意味します。OnClick()の例で、m_objectが内部的な目的でOnClick()を処理すると仮定します(例:ボタンなど)。このカスタム・イベント なしでクリックがあったことをCAnyClass内で知る必要がある場合、コードはどのように見えるでしょうか?
正直なところ、それはすべての目的のために毎日必要とする機能ではありませんが、方向性だけでなく通信する必要がある状況がある場合、それは解決策です。
元のスレッドの問題に戻りましょう。このアイデアは、価格に反応する複数の行を管理するために、配列を使用することでした。これらのライン・オブジェクトは、そのラインがローソク足と交差したときにイベントを処理し、何らかのアクションを強制します。私は、コンテナを使用することをお勧めします。このコンテナがこれらのアクションをカウントしたい場合、例えば、コンテナがカスタムイベントの受信者であることをすべてのオブジェクトに伝えるとき、この方法で簡単に行うことができます。
m_trendline[n].CustomEventReceiver(PTR(this));
CTrendLineクラスは、もちろん、このように実装しなければならない。
return OnLineCrossed()&CustomEvent(CTRENDLINE_CROSSED);
残念な ことに、 私は 2 週間の 休暇に 入ります。飛行機は数時間後に出発します(まあ、 もっと 悪いかも しれませんが)。
もうこの 時点で一つ 質問が あります。 MQLの フレーム ワークに関する 詳細なドキュメントは どこかにある のでしょうか?
Willbur
..
もうこの 時点で一つ 質問が あります。 MQLの フレーム ワークに関する 詳細なドキュ メントはどこかにある のでしょうか?
ないですね:-)
私の経験では、「mqlフレームワーク」を勉強するのは良いことだと思います。ただ、Doerkさんがおっしゃるように、標準ライブラリには 問題が多く、私見ですが、本格的な大型プロジェクトには使えないと思います。
下から上へ...
- stdlibは、オリジナルのobject.mqhに含まれていないのでしょうか?私はここでそれを必要としないが、それは2つのダブルを比較する唯一の信頼できる方法であるCompareDouble()を含んでいます。
- 私は標準では二重定義を避けるために#ifndefを使用し、条件付きコンパイルに使用します
- はい、三角形のメッセージングのために
- バイナリ&と論理バージョン&&はboolの結果で同じです。
- 埋め込みとは、外来クラスのインスタンスやオブジェクトが他のクラスの一部であり、両者が互いに派生していない場合を意味します。OnClick()の例で、m_objectが内部的な目的でOnClick()を処理すると仮定します(例:ボタンなど)。このカスタム・イベント なしでクリックがあったことをCAnyClass内で知る必要がある場合、コードはどのように見えるでしょうか?
正直なところ、それはすべての目的のために毎日必要とする機能ではありませんが、方向性だけでなく通信する必要がある状況がある場合、それは解決策です。
元のスレッドの問題に戻りましょう。このアイデアは、価格に反応する複数の行を管理するために、配列を使用することでした。これらのライン・オブジェクトは、そのラインがローソク足と交差したときにイベントを処理し、何らかのアクションを強制します。私は、コンテナを使用することをお勧めします。このコンテナがこれらのアクションをカウントしたい場合、例えば、コンテナがカスタムイベントの受信者であることをすべてのオブジェクトに伝えるとき、この方法で簡単に行うことができます。
m_trendline[n].CustomEventReceiver(PTR(this));
CTrendLineクラスは、もちろん、このように実装しなければならない。
return OnLineCrossed()&CustomEvent(CTRENDLINE_CROSSED);
stdlibはMQL4だけだと思っていたのですが、もしかしたら間違っていたのかもしれません。
すみません、なぜCObject全体を#ifndefの中に入れないといけないのかが分かりませんでした。このままだと二重定義になってしまうのでしょうか?あと、CObjectの上にCStructを空のクラスとして置いているのはなぜですか?
組み込みクラスについてですが、(私も25年来のプログラマーですが、OOではありません)あなたの例は、例えばこんな状況を指しているのでしょうか?例えば、私がCCarクラスで、CWheelクラスを埋め込んだとします。
そして、CWheelは空気圧の最小値か何かのイベントハンドラを持っていて、車である私はそれを知る必要があるのでしょうか?
この例と似たようなもの、あるいは他の具体的な例があれば教えてください。どのクラスがイベントを発生させ(クリックの例では明らかにチャートです)、誰がそれを処理するかという点で、私はまだそこに到達していません。また、技術的な面でも、例えば次のような行を理解することができます(その目的は、コンテナが、バーによって価格を横切るトレンドラインを管理する作業をどのように行うかを示すことだと思います)。
m_trendline[n].CustomEventReceiver(PTR(this)).CustomEventReceiver(PTR(this));
ループですべてのトレンドライン[1..n]を呼び出していますか? もしそうなら、コンテナが今処理しているのはどのような種類の一般的なイベントでしょうか?
CTRENDLINE_CROSSED イベントをトリガーする可能性のある新しいバーや価格変化のようなものでしょうか?そして、なぜそれは各行にGetPointer(this)を送るのでしょうか?
その行はコールバック・コンテナでなければならないのでしょうか?
ということで、もしそうであれば
return OnLineCrossed()&CustomEvent(CTRENDLINE_CROSSED);
とすると、各ラインはそれ自身のOnLineCrossed()を呼び出します。これは、価格がその特定のラインによって交差されたかどうかをチェックするだけの通常のメソッドであるべきです。
そして、CustomEvent(CTRENDLINE_CROSSED) - これは、ChartCustomEvent(...)を呼び出してCTRENLINE_CROSSEDイベントを発生させるだけです - この構造は、コンテナの中で再び処理されます? 最後の部分は、三角通信になりますか、私はちょうどここに2つの異なる概念を混在させているかもしれません。つまり、コンテナはCTRENDLINE_CROSSEDを処理するCustomEventハンドラを持っているのでしょうか?
を書くと、いくつかのことがより明確になると思います(そして、あなたが望むなら、CCarは無視することができ、単にトレンドラインに焦点を当てる)しかし、まだ私はなぜ各ラインにGetPointer(これ)を移動するのか分からないのですか?また、例えばどのようなイベントでコンテナは価格の変化を検出するために、各ラインのカスタムイベントレシーバを呼び出すのでしょうか、そして三角形の通信はどこにあるのでしょうか、それとも三角形のための前の例だけを適用するのでしょうか(CAnyClassと)?
このトレンドラインに三角形の例を適用することは可能でしょうか?
私は本当にあなたの時間と忍耐と助けにこれまで感謝します、それは全く明白ではありません。イベント駆動型プログラミングの可能性について、私の目を開かせてくれたと言わざるを得ません。