欲にまかせてMT5用のEA作成をしてるのですが、良くある(だろう)インターフェースを実装する形でのオブザーバーパターンなコードを書いたら、コンパイラに怒られました。
コンパイラに怒られる例
class CAnyEvent { /*色々と*/ };
interface IAnyEventListener {
public:
void onAnyEvent(const CAnyEvent&);
};
class CBase1 { /*なんやかんや*/ };
class CDerivesAndImplements : public CBase1, IAnyEventListener { /* <-多重継承禁止に引っかかる*/
public:
void onAnyEvent(const CAnyEvent&)override;
};
まあ怒られますよね。'implements'てのが無いんだから。
それがinterfaceであるなら、クラスの多重継承禁止の対象にはしないというようにしてくれるコンパイラになってくれんかな、とか思いますが、現になってないんだから仕方がない。
「どうしたもんだか」と悩んだ末に、ひとまずやってみて、一応望んだ通りに動作してくれたのは以下のコード。(CAnyEvent と IAnyEventListener は省略)
結局こうした
// IAnyEventListenerを実装するクラス
// これを一段かませて、実際のリスナーの仕事をするメソッドを呼び出す
template <typename OUTER>
class CAnyEventListener : public IAnyEventListener {
public:
CAnyEventListener(OUTER *o) : outer(o) {}
void onAnyEvent(const CAnyEvent &evt)override {
outer.onAnyEvent(evt);
};
private:
OUTER *outer;
};
class CAnyEventSource {
public:
void addListener(IAnyEventListener*);
};
class CBase1 { /*なんやかんや*/ };
class CListener1 : public CBase1 /*implements IAnyEventListener <-これが出来れば問題無かったのだけど*/ {
public:
// コンストラクタで、
// IAnyEventListener を実装したリスナーオブジェクトに、
// 自身の存在をセットしておき、イベント発生時には
// 自身のonAnyEventを呼んでもらう
CListener1() : anyEvtListener(GetPointer(this)) {}
// イベントソースにリスナーオブジェクトをセットする
// (自身をセットするのではない)
void setAnyEventSource(CAnyEventSource &src) {
src.addListener(GetPointer(anyEvtListener));
}
// 実際にリスナーとしての作業をするメソッド
void onAnyEvent(const CAnyEvent &evt) {
/* ........ */
}
private:
// IAnyEventListenerインターフェースを実装したリスナーオブジェクト
CAnyEventListener<CListener1> anyEvtListener;
};
という感じで、いちおう機能するものにはなりました。
しかし回りくどい。
なんか良い手は無いでしょうかね。