4

これがだまされている場合は申し訳ありませんが、正しい答えが見つかりません。

基本クラスのメンバーから関数を呼び出し、それをサブクラスのバージョンに解決したいと考えています。virtual と宣言すればできると思ったのですが、そうではありません。これが私のアプローチです:

class GUIWindow
{
public:
    GUIWindow()
    {
        SetupCallbacks();
    }

    virtual void SetupCallbacks()
    {
         // This function always called
    }
};

class GUIListbox : public GUIWindow
{
public:
    void SetupCallbacks()
    {
        // This never called
    }
};

GUIListbox lb; // GUIWindow::SetupCallbacks is called :(

私は何を間違っていますか?

どうもありがとう

4

5 に答える 5

8

コンストラクターで仮想関数を呼び出さないでください。

于 2010-02-27T16:36:37.253 に答える
3

一部のクラスの構築C中 (つまり、コンストラクターCがアクティブな間) に仮想関数を呼び出すと、仮想メカニズムは機能しますが、制限モードで機能します。クラス階層内の仮想呼び出しの解決は、現在構築中のクラスによって制限Cされます ( )。これは、クラスCが階層内の「最終」クラスであるかのように、仮想呼び出しが解決されることを意味します。

同じことがデストラクタにも当てはまります。

あなたの例では、 class のコンストラクターから仮想関数を呼び出していますGUIWindow。のコンストラクターがアクティブである限りGUIWindow、その仮想メカニズムは、 から派生した他のクラスがないかのように機能しGUIWindowます。GUIListboxこのメカニズムは、クラスの存在を完全に無視します。これが、存在しないかのように、仮想呼び出しの解決がGUIWindowand 呼び出しで「停止」する理由です。GUIWindow::SetupCallbacksGUIListbox::SetupCallbacks

C++ FAQ http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5で読むことができ ます

于 2010-02-27T17:08:18.020 に答える
1

派生型はまだ構築されていません。

Class Cat : Animal
{
//...
};

create a Cat オブジェクトを作成すると、次のことが起こります。

  1. 動物の構築
  2. 構築猫

オブジェクトが範囲外になるか、ヒープ上にある場合は削除によって破棄されると、次のことが起こります。

  1. 破壊猫
  2. 動物を破壊する

このため、コンストラクタまたはデストラクタで仮想関数を呼び出さないでください。基本クラスに実装がない場合は、純粋な仮想関数呼び出しさえあります。

次のことを行う必要があります。

GUIListbox lb;
lb.SetupCallbacks();

仮想のポイントは、次のようなことができるようにすることです。

GuiWindow *lb = new GuiListbox();
lb->SetupCallback();//Gets correctly resolved to GuiListBox's version
于 2010-02-27T16:40:12.690 に答える
0

問題は、コンストラクターから仮想関数を呼び出そうとしていることです。基本クラスのコンストラクターは派生クラスのコンストラクターの前に呼び出されるため、基本クラスのコンストラクターが実行されるとき、オブジェクトの "派生部分" はまだ作成されません。

基本クラス コンストラクターが終了し、派生クラス コンストラクターが開始されるまで、オブジェクトは基本クラス型のオブジェクトのように動作します。つまり、仮想関数の呼び出しは、派生クラスで定義された実装を呼び出さず、基本クラスのバージョンを実行するだけです。

詳細考えられる回避策については、C++ FAQ liteも参照してください。

于 2010-02-27T16:41:54.730 に答える
-1

GUIListbox簡単な答えは、を呼び出すコンストラクターを宣言する必要があるかもしれないということですSetupCallbacks。理由はもっと複雑です: GUIListbox はコンストラクターを宣言しないため、その型のオブジェクトを宣言するとGUIWindowコンストラクターが呼び出されます。コンストラクターが実行されているときGUIWindow、オブジェクトはまだ GUIListbox ではありません。コンパイラの観点からは、そのクラスの (空の) コンストラクターが開始されると、GUIListbox になります。したがって、最初のコンストラクターが実行されると、GUIWindow のメソッドが呼び出されます。IOW、これは機能せず、C++ で希望どおりに機能することはありません。

この落とし穴について詳しく説明しているリファレンスを次に示します: http://www.artima.com/cppsource/nevercall.html

そして、これは私のお気に入りの C++ リソースからの説明です: http://yosefk.com/c++fqa/inheritance-mother.html#fqa-23.5

于 2010-02-27T16:39:46.473 に答える