1

派生クラス オブジェクトを指す基本クラス ポインターを使用して仮想関数を呼び出す場合、コンパイラは動的バインディングを使用して派生バージョンを呼び出すことを知っています。しかし、基本クラス オブジェクトを指す基本クラス ポインターを使用して仮想関数を呼び出す場合、コンパイラは動的バインディングまたは静的バインディングを使用して仮想関数を呼び出しますか?

例えば:

class Base
{
public:
    virtual void show()
    {
        cout << "base class";
    }
}
int main()
{
    Base *pb; //Base class pointer
    Base b;   //Base class object
    pb = &b;
    pb->show(); //Is static binding or dynamic binding?
}

私の英語はとても下手なので、質問はできるだけ簡単にしたいのですが、以下に詳しく説明します。

実際の問題は、動的バインディングをトリガーする方法を要約していることに起因します。最初に、トリガー条件を要約します。

  1. 関数は仮想関数でなければなりません。
  2. 関数を呼び出すには、ポインターまたは参照を使用する必要があります。

2 つのトリガー条件は、「基本クラスのポインターが基本クラスのオブジェクトを指している場合、コンパイラーは動的バインディングを使用するかどうか」という問題を引き起こします。

私は検索回答のグーグルを持っていて、フラグメントを見つけました(デモはこちらです):

struct A {
   virtual void f() { cout << "Class A" << endl; }
};

struct B: A {
   //Note that it not overrides A::f.
   void f(int) { cout << "Class B" << endl; }
};

struct C: B {
   void f() { cout << "Class C" << endl; }
};

int main() {
   B b; C c;
   A* pa1 = &b;
   A* pa2 = &c;
//   b.f();
   pa1->f(); 
   pa2->f();
}

上記の例の出力は次のとおりです。

"Class A"
"Class C"

pa1->f()will outputに従ってClass A、3 番目のトリガー条件を要約します。

3.基本クラスの関数は、派生クラスでオーバーライドする必要があります。

3 つのトリガー条件に従って、基本クラス オブジェクトを指す基本クラス ポインターを使用して仮想関数を呼び出す場合、仮想関数はオーバーライドされないため、コンパイラは静的バインディングを使用して仮想関数を呼び出します。

ただし、派生クラス オブジェクトを指す派生クラス ポインターを使用して仮想関数を呼び出す場合、仮想関数がオーバーライドされるため、動的バインディングが使用されます。

とても混乱しました。

4

3 に答える 3

3

どれだけ賢く、どれだけうまく検出できるかに応じて、どちらかを選択するか、どちらも選択しないことができます。ルールは、ポリモーフィズムが機能しなければならないということです。これがどのように達成されるかは、実装の詳細です。

この場合のように、動的バインディングと静的バインディングの両方で同じ最終結果を達成できる場合、両方ともコンパイラの有効なオプションです。

あなたの場合、関数を呼び出す必要はまったくありません-生成されたコードは、によって生成されたコードとまったく同じになる可能性があります

int main()
{
    cout << "base class";
}
于 2013-08-19T13:25:47.207 に答える
2

コンパイラの最適化に依存していると思います。Base::showコンパイラは、それが常に呼び出されるかどうかを判断するのに十分賢いかもしれません。分解を見ればわかります。で静的バインディングを強制できますb->Base::show()

于 2013-08-19T13:26:23.440 に答える