class A {};
class B : public A {};
class C : public B {};
class X {
public:
virtualint g( C* c1, C* c2 ) { return ( 1 ); } //полное совпадение здесьvirtualint g( C* c, B* b ) { return ( 2 ); }
};
class Y : public C { //здесь ошибся, должно быть public : X
public:
virtualint g( A* a, B* b ) { return ( 3 ); }
};
voidOnStart()
{
C* c = new C;
Y* y = new Y;
Print( y.g( c, c ));
}
class A {};
class B : public A {};
class X {
public:
virtualint g( A* a )
virtualint f( B* a )
};
class Y : public X {
public:
virtualint g( A* a ) //подмена X::gvirtualint f( A* a ) //сокрытие X::f
};
class A{
public:
voidoperator= (const A* from){
if (GetPointer(this) == GetPointer(from)) // а тут я передаю и все ок
Alert(1); // резутат 1 из за того что передаю this
elseAlert(2);
}
};
class B : public A{
public:
voidoperator= (const B& from){
if (GetPointer(this) == GetPointer(from))
return;
operator=((A*)(GetPointer(this)));
}
};
B b;
B bb; // забыл написать создание объектов и вызов функции.
b = bb;
そうなんです。完全一致が優先されます。そして、それは本当に正しいのです。
なぜ、そのような統一が必要なのでしょうか?誤って設計されたプログラムの処理の一元化
C++とMQLで同じコードが同じように動作するように統一する必要があります。C++では、この順序は理由があって(!)行われます(そうしないと、ある時点で曖昧さが生じます)。当初はC++コンパイラの非論理性、あるいはバグだと考えていましたが、今ではこのようなアプローチには客観的な理由があると考えるようになりました。以下はMQLでの例ですが、X:: gは完全一致なのに、C++と同様にY:: gが呼ばれることがわかります。これは前の例と矛盾していますね。https://www.mql5.com/ru/forum/1111/page1223#comment_1074757
結果:3
C++は「非論理的」だが曖昧さのない順序を持ち、MQLはランダムな順序を持つことが判明した - 型が完全に一致する場合、一方では基底クラスが、他方では派生クラスが呼ばれる
C++とMQLで同じコードが同じように動作するように統一する必要があります。C++では、この順番は理由があって(!)行われます。当初はC++コンパイラの非論理性、あるいはバグだと考えていましたが、今ではこのようなアプローチには客観的な理由があると考えるようになりました。 以下はMQLの例で、X:: gは完全一致なのに、C++と同様にY:: gが呼ばれることを示しており、先の例と矛盾していることがわかります。
結果:3
C++は「非論理的」だが曖昧さのない順序を持ち、MQLはランダムな順序を持つことが判明した。
具体的にはどのC++の実装のことでしょうか?この実装はC++規格にどの程度対応しているのでしょうか。C++の規格では、オーバーロードされた関数の選択についてどのように書かれているのですか?
実は、あなたが言う関数のオーバーロードは、間違った設計の結果なのです。
ソースコードの移植は神話である。テストプログラムだけは、異なるC++環境でも同じように動作します。実際のプログラム(私たちは、実際の応用価値を持つ何千行ものコードについて話しています)は、異なる環境において、少なくともいくつかの側面において異なる動作をします。それに、MQLとC++の統一なんて、まったく話にならないし......遺伝子の無駄遣いです。
C++とMQLで同じコードが同じように動作するように統一する必要があります。C++では、この順序は理由があって(!)行われます(そうしないと、ある時点で曖昧さが生じます)。当初はC++コンパイラの非論理性、あるいはバグだと考えていましたが、今ではこのようなアプローチには客観的な理由があると考えるようになりました。以下はMQLでの例ですが、X:: gは完全一致なのに、C++と同様にY:: gが呼ばれることがわかります。これは前の例と矛盾していますね。https://www.mql5.com/ru/forum/1111/page1223#comment_1074757
結果:3
C++は「非論理的」だが曖昧さのない順序を持ち、MQLはランダムな順序を持つことが判明した - 完全な型マッチングの場合、あるケースでは基底クラスが、別のケースでは派生クラスが呼び出される
C++の規格では、オーバーロードされた関数を選択する順番について、どのように書かれているのでしょうか?
Strawstrup氏の言葉を借りれば、「C++では、基底クラスの仮想関数と 派生クラスの代用関数が完全に型一致する必要がある」のだ。
今、この問題を調べてみて、C++が正しいという結論に達しました。上記の2つの例では、派生クラスのg()はベースクラスのg()を代替するのではなく、隠蔽しています。そして、仮想化機構は置換が行われるときにのみ作動し、置換には(戻り値の型を除いて)正確な型合わせが必要です。特定の実装に依存できるのは、戻り値の型の精度だけです。
この例では勘違いしているようですが、もしクラスYがCではなくXから継承された場合、動作は前の例と同じになるはずです。
そう、私はここで勘違いをしていたのです。つまり、C++もMQLも置換と隠蔽の順序は曖昧ではないが、異なるということがわかったのです。代用と隠蔽の違いについては、前の記事での私の主張をご覧ください。
C++がhide時に警告を出すのは、この順番が意図的に選ばれていることを物語っている
そう、私はここで勘違いをしていたのです。つまり、C++もMQLも置換と隠蔽の順序は曖昧ではないが、異なるということがわかったのです。代用と隠蔽の違いについては、前の記事での私の主張をご覧ください。
C++がhide時に警告を出すのは、この順番が意図的に選ばれていることを示している
投稿ありがとうございます、議論(考える)します。
メソッド(関数)を検索する際のMQLコンパイラは、例えばMS C++でそうであるように、親に渡すことをキャストと見なしません。
メッセージありがとうございます、検討します。
MSだけでなく、Borland C++ 5.5.1も使用しました。
Stroustrupは、そうしないと "クラスオブジェクトの 終わりを越える "ことに関連した不快な結果が生じるかもしれないと書いている。
Strawstrup氏の言葉を借りれば、「C++では、ベースクラスの仮想関数と 派生クラスの置換関数が完全に型一致することが必要」なのだ。
今、この問題を調べてみて、C++が正しいという結論に達しました。上記の2つの例では、派生クラスのg()はベースクラスのg()を代替するのではなく、隠蔽しています。そして、仮想化機構は置換が行われるときにのみ作動し、置換には(戻り値の型を除いて)正確な型合わせが必要です。特定の実装に依存できるのは、戻り値の型の精度だけです。
ちょっと待ってください、ちょっと待ってください。異なるパラメータを持つ関数のオーバーロードについて話しています。
一方、仮想関数は、常に同じ型のパラメータを持ちます。仮想機能については、今回の議論の対象外です
MSだけでなく、Borland C++ 5.5.1も使用しました。
Stroustrupは、そうでなければ、"クラスオブジェクトの 終わりを越える "ことに関連した不快な結果が生じるかもしれないと書いている。
この問題は、既成のクラスに修正を加える場合(作業プログラム)にのみ関係します。
親がより適切な機能を持った後、プログラムは突然動かなくなります。なぜなら、子孫のメソッドの代わりに親のメソッドが呼び出されたからです。
さて、MQLの動作を変更すると、同じような状況が発生します。新しいメソッドを子孫に追加すると、親関数の代わりに(パラメータ・キャストなしで)子孫メソッドが呼び出され、パラメータ・キャストで、プログラムが再び動作しなくなります。
したがって、C++との互換性以外の問題は解決されませんし、コンパイラの動作の変更は既存のMQLプログラムにも影響します。
Так как переменные типа структур и простых типов не имеют указателей, то применять к ним функцию GetPointer() запрещено.
また、関数の引数としてポインタを渡す ことも禁止されています(GetPointerと どっちがいいんだろう?)これらの場合、コンパイラはエラーを報告 します。ドキュメントから引用します。
なぜアラートで叱らないのか、それは関数に間違ったポインタを渡してしまった私のせいだと、もう理解しています。