C++11 从EEPROM读取时,使用结构和虚拟继承是一个坏主意吗?(阿杜伊诺)

C++11 从EEPROM读取时,使用结构和虚拟继承是一个坏主意吗?(阿杜伊诺),c++11,casting,arduino-uno,virtual-inheritance,eeprom,C++11,Casting,Arduino Uno,Virtual Inheritance,Eeprom,我遇到了一个奇怪的问题,如果我从EEPROM加载我的数据结构,它会错误地转换它。但是,如果我对负责保存数据结构的函数和负责读取数据结构的函数都进行了函数调用,那么它会成功地将数据强制转换到我的结构中 我对这个问题进行了一些讨论,我注意到,如果您以uint8\t的形式读取数据,则保存的数据和从EEPROM读取的数据总是正确的。但由于某种原因,当程序中未使用保存功能且我们仅从EEPROM读取数据时,它无法将数据转换到我的数据结构(BareKeyboardKey2) 我认为以下结构是导致问题的原因:

我遇到了一个奇怪的问题,如果我从EEPROM加载我的数据结构,它会错误地转换它。但是,如果我对负责保存数据结构的函数和负责读取数据结构的函数都进行了函数调用,那么它会成功地将数据强制转换到我的结构中

我对这个问题进行了一些讨论,我注意到,如果您以
uint8\t
的形式读取数据,则保存的数据和从EEPROM读取的数据总是正确的。但由于某种原因,当程序中未使用保存功能且我们仅从EEPROM读取数据时,它无法将数据转换到我的数据结构(
BareKeyboardKey2

我认为以下结构是导致问题的原因:

// testStruct.h

struct IKey2
{
    int pin;
};

struct BareKeyboardKey2 : virtual IKey2
{
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};
// testStruct.h
struct IKey2
{
};

struct BareKeyboardKey2 : virtual IKey2
{
    int pin;
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};
第一次调用SaveStruct然后调用LoadStruct时的输出示例。(我保存到EEPROM的数据是一个
裸键盘键2(2,4)

// testStruct.h

struct IKey2
{
    int pin;
};

struct BareKeyboardKey2 : virtual IKey2
{
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};
// testStruct.h
struct IKey2
{
};

struct BareKeyboardKey2 : virtual IKey2
{
    int pin;
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};
读取:0x68 0x1 0x4 0x0 0x2 0x0
pin:2,钥匙代码:4

正如您所见,它正确地投射了
裸键盘键2
,但是。。。 以下是仅调用LoadStruct时的输出示例(前面示例中的相同数据存储在EEPROM上):

// testStruct.h

struct IKey2
{
    int pin;
};

struct BareKeyboardKey2 : virtual IKey2
{
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};
// testStruct.h
struct IKey2
{
};

struct BareKeyboardKey2 : virtual IKey2
{
    int pin;
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};
读取:0x68 0x1 0x4 0x0 0x2 0x0
pin:-18248,钥匙代码:4

如您所见,从EEPROM读取的数据(即
0x68 0x1 0x4 0x0 0x2 0x0
)在两个示例中是相同的,但在后一个示例中,它无法正确地将数据转换为裸键盘key2(
pin:-18248,keycode:4

我发现,如果我将结构更改为以下内容,无论我是使用
SaveStruct
LoadStruct
还是仅使用
LoadStruct

// testStruct.h

struct IKey2
{
    int pin;
};

struct BareKeyboardKey2 : virtual IKey2
{
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};
// testStruct.h
struct IKey2
{
};

struct BareKeyboardKey2 : virtual IKey2
{
    int pin;
    int keyCode;
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};
我还发现,如果我像这样将两个变量移动到IKey2中…:

struct IKey2
{
    int pin;
    int keyCode;
};

struct BareKeyboardKey2 : virtual IKey2
{
    BareKeyboardKey2() {}
    BareKeyboardKey2(int _pin, int _keyCode)
    {
        pin = _pin;
        keyCode = _keyCode;
    }
};
…这会导致程序将两个变量都转换为错误。示例输出:
pin:-18248,keycode:-18248


是什么导致了这种行为?我该怎么做才能使它保持一致?

我找到了解决问题的方法。我不是100%确定它是正确的,但这是我的理论

当将非POD结构作为字节保存到EEPROM时,它不会保存主结构和连接到结构的虚拟对象之间的连接。因此,数据是相同的,但如果使用调试器查看对象(在我的例子中是gdb)您将看到连接主结构和虚拟对象的虚拟ptr是一个无效指针。尽管如此,主结构中最初存在的其余数据仍然完好无损

因此,在我的例子中,为了解决这个问题,我通过从结构中删除虚拟继承,将结构转换为POD类型。相反,我使用了“Has a”关系,到目前为止,我的数据从EEPROM中正确读取,而不考虑上面使用的不同情况