【问题标题】:Odd behavior without virtual inheritance [duplicate]没有虚拟继承的奇怪行为[重复]
【发布时间】:2018-06-04 07:41:56
【问题描述】:

我正在编写一段代码,该代码表现出非常奇怪的行为。我设法在一个简单的 hello world 风格的程序中复制它,以下是代码:

#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 实际上被调用了两次!

这种行为的根源是什么?如何在不使用virtual 继承的情况下重构代码以重现正确的行为?

【问题讨论】:

  • 你用的是什么编译器?无论如何,复制到g++.exe (Rev1, Built by MSYS2 project) 7.2.0
  • @underscore_d g++ 5.4.0-std=c++11编译
  • 我也可以不使用C++11 来复制它(对代码稍作改动)。
  • 好点:我用-std=c++14编译。
  • 如果ICallbackReceiver * 代替void *,这将按预期工作。可能某些类型信息丢失了。

标签: c++ c++11 inheritance virtual-inheritance


【解决方案1】:

问题是因为您进行了转换ConfigurableTest -> void * -> ICallbackReceiver,这是不允许的。您需要从void * 转换回相同类型的ConfigurableTest - 在这种情况下不会出错。

另见multiple inheritance: unexpected result after cast from void * to 2nd base class

【讨论】:

    猜你喜欢
    • 2014-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    • 1970-01-01
    • 2017-03-31
    • 2011-10-19
    相关资源
    最近更新 更多