2017-05-16 19 views
2

オブジェクトのスライシングと多相の概念を試しながら、私が期待していたこのコード例を思いつきました。派生したFunctorTrueクラスの関数呼び出し演算子は、親のFunctorクラスの代わりに呼び出されます。オブジェクトのスライスはコンストラクタの実装に依存していますか?

注:run this example in Ideoneにすることができます。

class Dispatcher { 
public: 
    const Functor & mFunctor; 
    Dispatcher(const Functor & functor): mFunctor(functor) {} 
    Dispatcher(const Functor && functor): mFunctor(functor) { 
     cout << "Constructor with rvalue" << endl; 
    } 

    void dispatch(){ 
     cout << boolalpha << mFunctor() << endl; 
    } 
}; 

int main() { 
    Dispatcher dt = Dispatcher(FunctorTrue()); 
    dt.dispatch(); // returns false 
} 

注:あなたがalso run this example in Ideoneでき

は、私はラインを印刷するDispatcherクラスのコンストラクタを変更した場合、親の関数呼び出し演算子が代わりに呼び出されますことを見出しました。予期しない動作が原因Dispatcherクラスのメンバ変数mFunctorのタイプで、dispatch方法が唯一の効果的の関数呼び出し演算子を呼び出して、オブジェクトの「基底クラス部分」について知っている、と考えるのは私を導いたこと

基本クラスしかし、それは元の例では当てはまりません。私はすべてを混乱させてしまいます。

私の質問は以下のとおりです。

1)なぜコンストラクタの変化はFunctor > FunctorTrueクラス階層に呼び出されるメソッドを変更していますか?

2)バリエーションがデフォルトのコンストラクタが行う最適化に関連する場合、その最適化とはどのように指定できますか?

ありがとうございます。

答えて

4

未定義の動作があります。

あなたのコンストラクタは、寿命が終了するオブジェクトへの参照を格納しており、次にdispatch()がそのオブジェクトの使用を試みます。

int main() { 
    Dispatcher dt = Dispatcher(FunctorTrue()); 
     // lifetime of FunctorTrue object ends here 

    dt.dispatch(); // Use of dt.mFunctor causes undefined behavior 
} 
+0

ありがとうございます!私が似たようなものを見つけたのは初めてのことかもしれません。誰かがその問題の根本的な原因を指摘するのは初めてです。未定義の動作は、私が通常バグの原因として考えているものではありません。あなたの応答は私にその変更を促してくれました^^ – levelont

+0

もう一度待ってください... 'FunctorTrue()'の寿命を一時的に延ばさない 'Dispatcher'クラスの' mFunctor'メンバの定数はどうですか? – levelont

+0

@levelont:一時的な有効期間は間接的に延長されません。メインの視点から考えてみましょう。どのようにして(一般的に)コンストラクタが参照を保持しようとしていたのでしょうか? –