私たちが持っていると言います:
_
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()
?
ありがとう...
派生クラスのgが呼び出されます。ベースで関数を呼び出したい場合は、呼び出します
Base::g();
代わりに。派生バージョンを呼び出したいが、基本バージョンを呼び出したい場合は、gの派生バージョンが最初のステートメントで基本バージョンを呼び出すように調整します。
virtual void g() {
Base::g();
// some work related to derived
}
ベースの関数が仮想メソッドを呼び出し、制御が派生クラスに転送されるという事実は、テンプレートメソッドのデザインパターンで使用されます。 C++の場合、 Non-Virtual-Interface として知られています。 C++標準ライブラリでも広く使用されています(たとえば、C++ストリームバッファには関数pub...
実際の作業を行う仮想関数を呼び出します。たとえば、pubseekoff
は保護されたseekoff
を呼び出します。この答えでその例を書きました: どのようにしてオブジェクトの内部状態を検証しますか?
Baseのコンストラクターでgを呼び出さない限り、Derived :: gです。 BaseコンストラクターはDerivedオブジェクトが構築される前に呼び出されるため、Derived :: gを論理的に呼び出すことはできません。まだ構築されていない変数を操作する可能性があるため、Base :: gが呼び出されます。
pBaseは、ベースへのポインターです。 pBase = new Derivedは、Derived-Derived is-a Baseへのポインターを返します。
したがって、pBase = new Derivedは有効です。
pBaseはBaseを参照するため、DerivedはBaseであるかのように見えます。
pBase-> f()は、Derive :: f()を呼び出します。
次に、コードで次のことを確認します。
Derive :: f()-> Base :: f()-> g()-but which g ??
それは、Derive :: g()を呼び出します。これは、pBaseが「指す」gであるためです。
回答:Derive :: g()
まあ...これがコンパイルされるかどうかわかりません。以下、
Base *pBase = new Derived;
次のものがない限り無効です:
Class Derived : public Base
それはあなたが意味したいですか?これがあなたが意味したいなら、
pBase->f();
次に、呼び出しスタックは次のようになります。
Derived::f()
Base::f()
Derived::g()
実際にコードを実行すると、Derived :: g()が呼び出されていることがわかります。
g()=仮想と定義したので、最も派生したg()はクラスのvtableで検索され、現在アクセスしているコードを入力します。
C++ FAQ仮想関数について を参照してください。
派生クラスのメソッドが呼び出されます。
これは、仮想関数を持つクラスおよびそれらの関数をオーバーライドするクラス内にvtableを含めるためです。 (これは動的ディスパッチとも呼ばれます。)実際に何が起こっているのか:クラスごとにvtableが1つしかないため、Base
に対してvtableが作成され、Derived
に対してvtableが作成されます。 pBase
は仮想でオーバーライドされている関数を呼び出しているため、Derived
のvtableへのポインターが呼び出されます。 _d_ptr
_(vpointerとも呼ばれます)と呼びます:
_int main()
{
Base *pBase = new Derived;
pBase->d_ptr->f();
return 0;
}
_
これで、d_ptrはDerived::f()
を呼び出します。これはBase::f()
を呼び出し、vtableを見て、使用するg()
を確認します。 vpointerはDerived
のg()
のみを知っているため、これが使用されます。したがって、Derived::g()
が呼び出されます。
テンプレートメソッドパターン を発明しようとしていると思います