将 QObject 转换为 void 指针或从 void 指针转换会丢失数据?

Casting QObject to and from void pointer looses data?

我尝试将我的对象与空指针相互转换。

这就是我的 class 继承的方式:

#ifndef EVERYTHING_H
#define EVERYTHING_H
 
#include <QString>
#include <QObject>
 
struct Base
{
public:
    const QString name;
    explicit Base(const QString& n)
        : name { n } {}
};
      
class A : public QObject, public Base
{
    Q_OBJECT
 
public:
    explicit A(QObject *parent = nullptr)
        : QObject(parent),
          Base("name") {}
};
 
#endif // EVERYTHING_H

这是我的主要内容:

#include <QApplication>
#include <QDebug>
#include "everything.h"

static A *a = new A();

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    qDebug() << qint64(a);
    qDebug() << a->name;

    auto aa = static_cast<Base*>(a);
    qDebug() << qint64(aa);
    qDebug() << aa->name;

    void* v = static_cast<void*>(a);
    aa = static_cast<Base*>(v);
    qDebug() << qint64(v);
    qDebug() << qint64(aa);
    qDebug() << aa->name;

    return app.exec();
}

输出为:

1983584
"name"
1983600
"name"
1983584
1983584
""
  1. 我不明白为什么第一个 aa 与原始指针的地址不同并且可以工作,而第二个 aa 突然指向原始地址但不起作用。
  2. 常量数据怎么会在这里丢失?在我的实际应用程序(不是这个最小的例子)中,我没有得到一个空字符串,而是一个断言错误:

ASSERT: "size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData)"

注意:如果 A 不是 QObject(只是 Base),一切正常,我每次都得到“name”。

我需要先从 A 施法到 Base,然后从 Base 施法到 void,然后再从 void 施法到 Base。演员的顺序显然需要颠倒。

在继承层次结构中向上或向下转换指针时,不能保证指针中的底层内存地址保持不变。根据所涉及的继承细节,可能需要进行调整以确保生成的指针最终指向对象的正确部分。 (例如,这种事情可以发生在多重继承中。)

通常情况下,编译器会为您处理这些细节,但是当您涉及 void* 时,您会阻止编译器知道发生了什么。因此,正确地做事完全取决于您。

在这种情况下:

A *a = new A();
auto aa = static_cast<Base*>(a);

编译器知道要进行哪些调整才能生成有效的 Base*

然而这里:

A *a = new A();
void* v = static_cast<void*>(a);
aa = static_cast<Base*>(v);

编译器获取a中的内存地址,直接复制到v,然后直接复制到aa。没有进行任何调整。所以通过颠覆编译器的类型知识,你最终遇到了问题。

我很确定我听说过您应该只从 void* 转换回最初转换为 void* 的确切类型。这种情况就是原因的一个例子。所以如果我们改变它:

A *a = new A();
void* v = static_cast<void*>(a);
A* aa = static_cast<A*>(v);
Base* base = static_cast<Base*>(aa);

那么你应该会发现它有效。