エラー、バグ、質問 - ページ 1206

 
stringo:

そうなんです。完全一致が優先されます。そして、それは本当に正しいのです。

なぜ、そのような統一が必要なのでしょうか?誤って設計されたプログラムの処理の一元化

C++とMQLで同じコードが同じように動作するように統一する必要があります。C++では、この順序は理由があって(!)行われます(そうしないと、ある時点で曖昧さが生じます)。当初はC++コンパイラの非論理性、あるいはバグだと考えていましたが、今ではこのようなアプローチには客観的な理由があると考えるようになりました。以下はMQLでの例ですが、X:: gは完全一致なのに、C++と同様にY:: gが呼ばれることがわかります。これは前の例と矛盾していますね。https://www.mql5.com/ru/forum/1111/page1223#comment_1074757

class A {};
class B : public A {};
class C : public B {};
class X {
public:
        virtual int g( C* c1, C* c2 ) { return ( 1 ); } //полное совпадение здесь
        virtual int g( C* c,  B* b )  { return ( 2 ); }
};
class Y : public C { //здесь ошибся, должно быть public : X
public:
        virtual int g( A* a, B* b ) { return ( 3 ); }
};
void OnStart()
{
        C* c = new C;
        Y* y = new Y;
        Print( y.g( c, c ));
}

結果:3

C++は「非論理的」だが曖昧さのない順序を持ち、MQLはランダムな順序を持つことが判明した - 型が完全に一致する場合、一方では基底クラスが、他方では派生クラスが呼ばれる

 
A100:

C++とMQLで同じコードが同じように動作するように統一する必要があります。C++では、この順番は理由があって(!)行われます。当初はC++コンパイラの非論理性、あるいはバグだと考えていましたが、今ではこのようなアプローチには客観的な理由があると考えるようになりました。 以下はMQLの例で、X:: gは完全一致なのに、C++と同様にY:: gが呼ばれることを示しており、先の例と矛盾していることがわかります。

結果:3

C++は「非論理的」だが曖昧さのない順序を持ち、MQLはランダムな順序を持つことが判明した。

具体的にはどのC++の実装のことでしょうか?この実装はC++規格にどの程度対応しているのでしょうか。C++の規格では、オーバーロードされた関数の選択についてどのように書かれているのですか?

実は、あなたが言う関数のオーバーロードは、間違った設計の結果なのです。

ソースコードの移植は神話である。テストプログラムだけは、異なるC++環境でも同じように動作します。実際のプログラム(私たちは、実際の応用価値を持つ何千行ものコードについて話しています)は、異なる環境において、少なくともいくつかの側面において異なる動作をします。それに、MQLとC++の統一なんて、まったく話にならないし......遺伝子の無駄遣いです。

 
A100:

C++とMQLで同じコードが同じように動作するように統一する必要があります。C++では、この順序は理由があって(!)行われます(そうしないと、ある時点で曖昧さが生じます)。当初はC++コンパイラの非論理性、あるいはバグだと考えていましたが、今ではこのようなアプローチには客観的な理由があると考えるようになりました。以下はMQLでの例ですが、X:: gは完全一致なのに、C++と同様にY:: gが呼ばれることがわかります。これは前の例と矛盾していますね。https://www.mql5.com/ru/forum/1111/page1223#comment_1074757

結果:3

C++は「非論理的」だが曖昧さのない順序を持ち、MQLはランダムな順序を持つことが判明した - 完全な型マッチングの場合、あるケースでは基底クラスが、別のケースでは派生クラスが呼び出される

この例では勘違いしているようですが、もしクラスYがCからではなくXから継承されていれば、動作は前の例と同じになるはずです。
 
stringo:

C++の規格では、オーバーロードされた関数を選択する順番について、どのように書かれているのでしょうか?

Strawstrup氏の言葉を借りれば、「C++では、基底クラスの仮想関数と 派生クラスの代用関数が完全に型一致する必要がある」のだ。

今、この問題を調べてみて、C++が正しいという結論に達しました。上記の2つの例では、派生クラスのg()はベースクラスのg()を代替するのではなく、隠蔽しています。そして、仮想化機構は置換が行われるときにのみ作動し、置換には(戻り値の型を除いて)正確な型合わせが必要です。特定の実装に依存できるのは、戻り値の型の精度だけです。

 
mql5:
この例では勘違いしているようですが、もしクラスYがCではなくXから継承された場合、動作は前の例と同じになるはずです。

そう、私はここで勘違いをしていたのです。つまり、C++もMQLも置換と隠蔽の順序は曖昧ではないが、異なるということがわかったのです。代用と隠蔽の違いについては、前の記事での私の主張をご覧ください。

C++がhide時に警告を出すのは、この順番が意図的に選ばれていることを物語っている

class A {};
class B : public A {};

class X {
public:
        virtual int g( A* a )
        virtual int f( B* a )
};
class Y : public X {
public:
        virtual int g( A* a ) //подмена  X::g
        virtual int f( A* a ) //сокрытие X::f
};
 
A100:

そう、私はここで勘違いをしていたのです。つまり、C++もMQLも置換と隠蔽の順序は曖昧ではないが、異なるということがわかったのです。代用と隠蔽の違いについては、前の記事での私の主張をご覧ください。

C++がhide時に警告を出すのは、この順番が意図的に選ばれていることを示している

メソッド(関数)を検索するときのMQLコンパイラは、MSのC++などでそうであるように、親に渡すことをキャストとみなさないのだそうです。

投稿ありがとうございます、議論(考える)します。

 
mql5:
メソッド(関数)を検索する際のMQLコンパイラは、例えばMS C++でそうであるように、親に渡すことをキャストと見なしません。

メッセージありがとうございます、検討します。

MSだけでなく、Borland C++ 5.5.1も使用しました。

Stroustrupは、そうしないと "クラスオブジェクトの 終わりを越える "ことに関連した不快な結果が生じるかもしれないと書いている。

 
A100:

Strawstrup氏の言葉を借りれば、「C++では、ベースクラスの仮想関数と 派生クラスの置換関数が完全に型一致することが必要」なのだ。

今、この問題を調べてみて、C++が正しいという結論に達しました。上記の2つの例では、派生クラスのg()はベースクラスのg()を代替するのではなく、隠蔽しています。そして、仮想化機構は置換が行われるときにのみ作動し、置換には(戻り値の型を除いて)正確な型合わせが必要です。特定の実装に依存できるのは、戻り値の型の精度だけです。

ちょっと待ってください、ちょっと待ってください。異なるパラメータを持つ関数のオーバーロードについて話しています。

一方、仮想関数は、常に同じ型のパラメータを持ちます。仮想機能については、今回の議論の対象外です

 
A100:

MSだけでなく、Borland C++ 5.5.1も使用しました。

Stroustrupは、そうでなければ、"クラスオブジェクトの 終わりを越える "ことに関連した不快な結果が生じるかもしれないと書いている。

MQLコンパイラの動作を変更するつもりはありません。これは「諸刃の剣」です。説明しよう。

この問題は、既成のクラスに修正を加える場合(作業プログラム)にのみ関係します。
親がより適切な機能を持った後、プログラムは突然動かなくなります。なぜなら、子孫のメソッドの代わりに親のメソッドが呼び出されたからです。
さて、MQLの動作を変更すると、同じような状況が発生します。新しいメソッドを子孫に追加すると、親関数の代わりに(パラメータ・キャストなしで)子孫メソッドが呼び出され、パラメータ・キャストで、プログラムが再び動作しなくなります。

したがって、C++との互換性以外の問題は解決されませんし、コンパイラの動作の変更は既存のMQLプログラムにも影響します。
 

Так как переменные типа структур и простых типов не имеют указателей, то применять к ним функцию GetPointer() запрещено.

また、関数の引数としてポインタを渡す ことも禁止されていますGetPointerと どっちがいいんだろう?)これらの場合、コンパイラはエラーを報告 します

ドキュメントから引用します。

class A{
public:
   void operator= (const A* from){
      if (GetPointer(this) == GetPointer(from))      // а тут я передаю и все ок
         Alert(1);                                  // резутат 1  из за того что передаю this
      else
         Alert(2);
   }
};

class B : public A{
public:
   void operator= (const B& from){  
      if (GetPointer(this) == GetPointer(from))
         return;
      operator=((A*)(GetPointer(this)));
   }
};
  B b;
   B bb;                        // забыл написать создание объектов и вызов функции.
   b = bb;

なぜアラートで叱らないのか、それは関数に間違ったポインタを渡してしまった私のせいだと、もう理解しています。