1

オーバーロードとオーバーライドの基本は理解していますが、何かが私を混乱させています。簡単な例を使用して説明します。

  • クラス B には関数 X(B& b) があります
  • クラス D はクラス B を継承しています。
  • クラス D は、X を X(B& b) でオーバーライドし、X(D& d) でオーバーロードします。

次に、次のコードがあります。

void test(D& d1, B& b1, D& d2, B& b2){
    d1.X(d2);
    d1.X(b2);
    b1.X(d2);
    b1.X(b2);
}

int main(){
    D d1, d2, d3, d4;
    test(d1, d2, d3, d4);
}

の 3 行目と 4 行目で、test()呼び出す X() の実装と、発生している一般的なメカニズムを決定する方法がよくわかりません。

4

2 に答える 2

2

で仮想関数Xを宣言し、派生クラスでB(B::X)オーバーライドします。とのパラメーター リストが異なり、異なると見なされる場合、はオーバーライドされず、仮想ではありません (virtual キーワードで宣言した場合を除きます)。代わりに、非表示にします。XD(D::X)B::XD::XB::XD::XD::XB::XD::XD::XB::X

#include <iostream>
using namespace std;

struct B {
   virtual void X() { cout << "Class B" << endl; }
};

struct D: B {
   void X(int) { cout << "Class D" << endl; }
};

int main() {
   D d;
   B* pb = &d;
//   d.X();
   pb->X();
}

を呼び出すことさえできません。d.X()によって隠されていD::X(int)ます。しかしpb->X()、大丈夫です。

だからあなたの場合:

struct B {
   virtual void X(B& b) { cout << "Class B" << endl; }
};

struct D: B {
   void X(B& b) { cout << "Class D" << endl; }
   void X(D& d) { cout << "Class D" << endl; }
};

D::Xを非表示にしB::Xます。Sod1.X(d2)d1.X(b2)intest()は とは何の関係もありませんB::X。And b1.X(d2)、 andb1.X(b2)test()を呼び出しますD::X。はB::XD では見えませんが、virtual キーワードでD::X(B&)宣言するかどうかに関係なく仮想です。D::X(B&)コンパイラはそれが仮想関数であることを認識しているためD::X(B&)、呼び出されます。

編集: b1.X(b2) の詳細説明、B::X は仮想関数であり、D::X はそれをオーバーライドするため、動的バインディングによって確実に D::X が呼び出されます。また、オーバーロードはコンパイル時に決定されるため、D::X(D&) は呼び出されません。

于 2013-03-03T02:39:26.520 に答える
1

関連する 2 つのステップがあります。オーバーロードの選択 ( X(B&)vs. X(D&)) と、それが完了したら、選択した関数の適切な実装を見つけることです。前者はコンパイル時に発生し、オブジェクトその引数の静的型に依存します。後者は実行時に発生し、オブジェクトの動的型に依存します (引数の動的型には依存しないことに注意してください)。

4 つのオブジェクトは次のように宣言されます。d1andd2D&であるため、それらの静的型D&であり、b1およびb2は として宣言されているB&ため、それらの静的型はB&です。静的型は、コードで宣言したものです。

しかし、4 つすべての動的タイプDは です。これは、4 つの参照すべてが実際にDは で-objectsとして作成したオブジェクトを参照するためですmain()

したがって、最初のステップ、オーバーロードの選択:b1.X(b2)との場合、b1.X(d2)可能なオーバーロードは 1 つだけです。これX(B&)は、静的型がB&であり、 のクラス定義にBこの 1 つの関数しかないためです。ただし、d1.X(b2)andの場合、静的型が であるため、d1.X(d2)オーバーロードの選択は のクラス定義に基づいています。したがって、 と の 2 つのオーバーロードが考慮されます。引数が の場合、前者のオーバーロードが選択され、引数が の場合、後者のオーバーロードが選択されます。これらはすべて、オブジェクトと引数の静的 (=宣言された) 型に基づいています。DD&X(B&)X(D&)b2d2

2 番目のステップでは、選択したオーバーロードの適切な実装を選択します。これは実行時に発生し、(引数ではなく) オブジェクトの動的な型に依存します。の場合、b1.X(b2)の動的型は であるため、b1D呼び出すことになりD::X(B&)ます。についても同じb1.X(d2): 前のステップで選択されたオーバーロードは でしX(B&)たが、選択された実装はD::X(B&)です。(D::X(D&)それは別のオーバーロードであり、オーバーロードは静的型に基づいて既に選択されているため、この時点では候補ではありません)。d1.X(b2)との場合、オブジェクトの動的タイプが静的タイプと同じであるためd1.X(d2)、選択された関数は最初の手順 とD::X(B&)と同じです。D::X(D&)

于 2013-03-03T03:21:34.390 に答える