2016-08-01 11 views
9

私はMicrosoft Visual C++ 2015で少し苦労しており、小さなプログラムで問題を再現することができました。C++:不可解な「純粋仮想関数呼び出し」エラー

class BaseClass { 
public: 
    BaseClass() 
     : mValue(0) 
     , mDirty(true) 
    {} 
    virtual ~BaseClass() {} 
    virtual int getValue() const { if(mDirty) updateValue(); return mValue; } 

protected: 
    virtual void updateValue() const = 0; 

    mutable bool mDirty; 
    mutable int mValue; 
}; 

class DerivedClass : public BaseClass { 
public: 
    DerivedClass() {} 

protected: 
    void updateValue() const override 
    { 
     mValue++; 
     mDirty = false; 
    } 
}; 

class Impersonator { 
public: 
    Impersonator() {} 

    // conversion operator 
    operator DerivedClass() const 
    { 
     return DerivedClass(); 
    } 

    // conversion method 
    DerivedClass toDerived() const 
    { 
     return DerivedClass(); 
    } 
}; 

、私は次の操作を実行したときに、私は「純粋仮想関数呼び出し」エラーを取得:以下のクラスを考えると、私はvoid use(const BaseClass&)機能を変更することはできませんことを考えると

void use(const BaseClass &inst) 
{ 
    // calls `getValue` which in turns calls the virtual function 'updateValue' 
    int value = inst.getValue(); 
} 

int main() 
{ 
    // creates a temporary, then passes it by reference: 
    use(DerivedClass()); // this works 

    // calls conversion operator to create object on stack, then passes it by reference: 
    DerivedClass i = Impersonator(); 
    use(i); // this works 

    // calls conversion method to create a temporary, then passes it by reference: 
    use(Impersonator().toDerived()); // this works 

    // calls conversion operator to create a temporary, then passes it by reference: 
    Impersonator j = Impersonator(); 
    use(j); // causes a pure virtual function call error! 

    return 0; 
} 

、私は何も変更することができますImpersonatorクラスで、デバッグエラーを生成せずに最後の呼び出しを使用できるようにするには?

+0

Visual Studioのランタイムコンポーネントは正常ですか?たぶん一部の欠落しているコンポーネントがその問題を引き起こします。 – pilkington

+1

'getValue'の最後の呼び出しの中でブレークポイントしてvtableポインタを調べると、MSVCは' BaseClass'オブジェクトを持っていると誤って考えます。 – Praetorian

+0

http://stackoverflow.com/questions/99552/where-do-pure-virtual-function-call-crashes-come-from –

答えて

2

私が見る問題を軽減する唯一の方法は、operator const BaseClass&()Impersonatorに追加し、DerivedClassへの参照を戻すことです。

これは、コンパイラが使用しようとしている問題のある/誤ったものよりも優れた変換を作成します。

は当然 Impersonator値で返すと一時を作成することができませんので、 DerivedClassオブジェクト、または多くのオブジェクトを所有する必要があり、かつ適切な時期に何とかそれらを配置します。このデモプログラムのために働く最も簡単な方法は、データメンバーへの参照を返すことですが、実際のプログラムは何か他のことをしなければならないかもしれません。

class Impersonator { 
public: 
    Impersonator() {} 

    // conversion operator 
    operator DerivedClass() 
    { 
     return d; 
    } 
    operator const BaseClass&() 
    { 
     return d; 
    } 

private: 
    DerivedClass d; 
}; 
+0

はい、それは動作します。残念ながら、実際のアプリケーションの「偽装者」はLightSourceクラスでカメラを偽装しようとしており、そのデータメンバーはstd140のレイアウトルールに厳密に従う必要があるため、DerivedClassデータメンバーを追加することはできません。私は変換演算子で静的なものを作成することができましたが、そのような "一時的な"ものはアクティブにすることができ、スレッドセーフでもありません。しかし、あなたの入力をありがとう。 –

+0

部分解:変換演算子ではなく、 'Impersonator'メソッドを使用して' DerivedClass'を作成すると、それは動作します: 'DerivedClass toDerived()const {return DerivedClass(); } '。これをサンプルコードに追加します。 –

+0

DerivedClassオブジェクトを動的に割り当て、スレッドローカルコンテナに配置することができます。 DerivedClassオブジェクトが必要になる可能性がないことが分かったら、それをクリーンアップしてください。または、 'use'をラップすることができる場合は、ラッパー内の動的オブジェクトを削除します。 –

1

これは回避策です。 のラッパーを作成し、const DerivedClass&を受け取ります。

//I get a "pure virtual function call" error when I do the following : 
void use(const BaseClass &inst) 
{ 
    // calls `getValue` which in turns calls the virtual function 'updateValue' 
    int value = inst.getValue(); 
} 

void use(const DerivedClass &inst) { 
    use(static_cast<const BaseClass&>(inst)); 
} 

良くマッチは、回避策ラッパーが選択されるので、正しいタイプの一時的に作成され、実際のuse実装に渡されたことへの参照を意味します。

関連する問題