1

{ Visual Studio 2010 、Win7 を使用 }

class Base
{
    public:
        Base() : terminateCondition(false)
        {
            //spawn new thread and set entry point to newThreadFunc()
        }

        virtual ~Base() // edited to say it's virtual.
        {
            terminateCondition=true;
            //wait for thread to join
        }

        virtual void vfunc() = 0;

        static void __stdcall newThreadFunc(void *args)
        {
            while(!terminateCondition)
                pThis->vfunc();
        }

        volatile bool terminateCondition;
};

class Derived : public Base
{
    public:
        virtual void vfunc()
        {
            //Do Something
        }
};

Derived* dPtr=new Derived; //now assume pThis is dptr
//later somewhere
delete dPtr;

このコードは、と言ってクラッシュしますpure virtual calledterminateCondition=trueのデストラクタに移動すると、Derivedこのクラッシュが回避されます。私は部分的に理由を理解していると思います。破壊は構築の逆順であるため、 の d'tor が最初に実行され、 の d'tor を呼び出す前にDerivedのすべての機能が破壊されます。その間にが発生すると、アプリケーションがクラッシュします。と呼ばれる純粋な仮想を言ってクラッシュします。この部分が理解できませんでした。誰か説明してくれませんか?DerivedBasepThis->vfunc()

4

2 に答える 2

5

基本クラスのデストラクタは である必要があります。virtualそうではないため、このコードはUndefined Behaviorを呼び出します。

参照:
C++03 標準: セクション 5.3.5/3:

オペランドの静的型がその動的型と異なる場合、静的型はオペランドの動的型の基本クラスであり、静的型は仮想デストラクタを持つ必要があります。そうしないと、動作が未定義になります。


コンストラクタ/デストラクタを介して仮想関数を呼び出すと、動的ディスパッチが期待どおりに機能しません。
コンストラクタ/デストラクタ内の型はthis、コンストラクタ/デストラクタが実行されているクラスの型です。動的ディスパッチがオーバーライドされた派生クラス メソッドを呼び出すことを期待していますが、最終的に定義のない呼び出しになり、未定義の動作が発生Derived::vfunc()ますBase::vfunc()

参照:
C++03 標準 10.4/6:

「メンバー関数は、抽象クラスのコンストラクター (またはデストラクタ) から呼び出すことができます。そのようなコンストラクターから作成 (または破棄) されるオブジェクトに対して、直接的または間接的に純粋仮想関数への仮想呼び出し (10.3) を行うことの効果 (またはデストラクタ) が定義されていません。」

于 2012-10-03T06:43:14.130 に答える
2

これは、まだ終了していないか、すでに開始されてvfuncいるときにコード内で呼び出すことができるために発生します。これらのケースは両方とも未定義の動作を引き起こし、通常は「純粋な仮想呼び出し」エラーとして現れます。エラーである理由は、ほとんどの派生オブジェクトのクラスのコンストラクターが実行を開始するまで「仮想」メカニズムが開始されず、ほとんどの派生オブジェクトのクラスのデストラクタが終了した後は「仮想」メカニズムが無効になるためです。ランニング。そのため、コンストラクターまたはデストラクタがオブジェクトで実行されている間に仮想関数を呼び出すと、コンストラクターまたはデストラクタが実行されているクラスの対応する関数が呼び出されます。そして、その関数がたまたま純粋な仮想である場合、動作は未定義です。Base::Base()Base::~Base()

ISO/IEC 14882:2003、10.4/6: メンバー関数は、抽象クラスのコンストラクタ (またはデストラクタ) から呼び出すことができます。そのようなコンストラクタ (またはデストラクタ) から作成 (または破棄) されるオブジェクトに対して、直接的または間接的に純粋仮想関数への仮想呼び出し (10.3) を行うことの効果は定義されていません。

于 2012-10-03T06:47:32.543 に答える