2017-12-21 17 views
4

非常に奇妙な振る舞いをするコードを作成しています。仮想継承のない奇妙な振る舞い

#include <iostream> 
using namespace std; 

class Test 
{ 
public: 
    virtual ~Test() = default; 

protected: 
    virtual void SetUp() { } 
}; 

class ICallbackReceiver 
{ 
public: 
    virtual ~ICallbackReceiver() = default; 
    virtual void onReady() = 0; 
}; 

// C-style callback 
void readyReceiver(void* userdata) 
{ 
    cout << "3) readyReceiver\n"; 
    static_cast<ICallbackReceiver*>(userdata)->onReady(); 
} 

using callback_t = void(*)(void*); 
callback_t myCallback; 
void* myUserData; 

void registerCallback(callback_t callback, void* userData) 
{ 
    cout << "2) registerCallback\n"; 
    myCallback = callback; 
    myUserData = userData; 
} 

class ConfigurableTest : public /*virtual*/ Test, public ICallbackReceiver 
{ 
public: 

    void SetUp() override 
    { 
     cout << "1) ConfigurableTest::SetUp\n"; 
     registerCallback(&readyReceiver, static_cast<void*>(this)); 
    } 

    void onReady() override 
    { 
     cout << "4) ConfigurableTest::onReady\n"; 
    } 
}; 

int main() 
{ 
    ConfigurableTest test; 
    test.SetUp(); 

    myCallback(myUserData); 

    return 0; 
} 

myCallbackが何かテストする必要が呼ばれるたび:私は、コードで以下、ハローシンプルな世界スタイルのプログラムでそれを複製することができました。そして、これは表示されるべき出力されます:

1) ConfigurableTest::SetUp 
2) registerCallback 
3) readyReceiver 
4) ConfigurableTest::onReady 

しかし、私はTestクラスのvirtual継承を指定しない限り、これは私が見出力されます:あなたが見ることができるように

1) ConfigurableTest::SetUp 
2) registerCallback 
3) readyReceiver 
1) ConfigurableTest::SetUp 
2) registerCallback 

ConfigurableTest::onReady呼び出されることはありませんが、実際にはConfigurableTest::SetUpが2回呼び出されます。

この動作の原因は何ですか? virtual継承を使用せずに正しい動作を再現するためにコードを再因子化するにはどうすればよいですか?

+0

どのコンパイラを使用しましたか?とにかく 'g ++ .exe(Rev1、MSYS2プロジェクトで構築されたRev1)7.2.0' –

+0

' -std = C++ 11'でコンパイルされた@underscore_d 'g ++ 5.4.0' – Nick

+0

私は' C++ 11'(コードを少し変更したもの)。 – Nick

答えて