64

私たちが持っているとしましょう:


Class Base
{   
    virtual void f(){g();};
    virtual void g(){//Do some Base related code;}
};

Class Derived : public Base
{   
    virtual void f(){Base::f();};
    virtual void g(){//Do some Derived related code};
};

int main()
{
    Base *pBase = new Derived;
    pBase->f();
    return 0;  
}

g()から呼び出されるのはどれBase::f()ですか? Base::g()またはDerived::g()

ありがとう...

4

9 に答える 9

65

派生クラスの g が呼び出されます。ベースで関数を呼び出したい場合は、

Base::g();

代わりは。派生バージョンを呼び出したいが、基本バージョンも呼び出したい場合は、 g の派生バージョンが最初のステートメントで基本バージョンを呼び出すように調整します。

virtual void g() {
    Base::g();
    // some work related to derived
}

ベースからの関数が仮想メソッドを呼び出すことができ、制御が派生クラスに転送されるという事実は、テンプレート メソッドの設計パターンで使用されます。C++ の場合は、 Non-Virtual-Interfaceとして知られています。C++ 標準ライブラリでも広く使用されています (たとえば、C++ ストリーム バッファにpub...は、実際の作業を行う仮想関数を呼び出す関数があります。たとえばpubseekoff、 protected を呼び出しますseekoff)。この回答でその例を書きました: How do you validate an object's internal state?

于 2008-12-29T09:52:41.680 に答える
17

Base のコンストラクターで g を呼び出さない限り、Derived::g です。Derived オブジェクトが構築される前に Base コンストラクターが呼び出されるため、まだ構築されていない変数を操作する可能性があるため、Derived::g を論理的に呼び出すことができず、Base::g が呼び出されます。

于 2013-09-19T04:18:01.497 に答える
6

pBase はベースへのポインタです。pBase = new Derived は Derived へのポインターを返します - Derived is-a Base。

したがって、 pBase = new Derived は有効です。

pBase は Base を参照するため、Derived が Base であるかのように見えます。

pBase->f() は、Derive::f(); を呼び出します。

次に、コードで次のことがわかります。

Delive::f() --> Base::f() --> g() - しかし、どの g??

それは、pBase が「指す」g であるため、Derive::g() を呼び出します。

答え: Deriv::g()

于 2010-05-28T20:56:32.187 に答える
2

うーん...これがコンパイルされるかどうかわかりません。以下、

Base *pBase = new Derived;

次の場合を除き、無効です。

Class Derived : public Base

それはあなたが意味したいですか?これがあなたの言いたいことなら、

pBase->f();

次に、コール スタックは次のようになります。

Derived::f()
    Base::f()
        Derived::g()
于 2008-12-29T19:20:54.527 に答える
1

実際にコードを実行すると、Derived::g() が呼び出されていることがわかります。

于 2008-12-30T07:30:04.977 に答える
1

g() を仮想として定義したため、最も派生した g() がクラスの vtable で検索され、コードが現在アクセスしている型に関係なく呼び出されます。

仮想関数に関する C++ FAQ を参照してください。

于 2008-12-29T10:15:35.330 に答える
0

派生クラスのメソッドが呼び出されます。

これは、仮想関数とそれらの関数をオーバーライドするクラスを持つクラス内に vtable が含まれているためです。(これは、動的ディスパッチとも呼ばれます。)実際に何が起こっているかを次に示します。クラスごとに 1 つの vtable しかないためBase、vtable が に対して作成され、vtable が に対して作成されます。Derivedは仮想でオーバーライドされた関数を呼び出しているためpBase、vtable へのポインターDerivedが呼び出されます。d_ptrvpointer とも呼ばれます。

int main()
{
    Base *pBase = new Derived;
    pBase->d_ptr->f();
    return 0;  
}

d_ptr が を呼び出しDerived::f()、これが を呼び出しBase::f()、vtable を調べて何g()を使用するかを確認します。vpointer は in のみを知っているため、それg()Derived使用します。したがって、Derived::g()と呼ばれます。

于 2016-06-23T01:51:19.850 に答える
0

Template Method Patternを発明しようとしていると思います

于 2008-12-29T10:06:30.340 に答える