Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将QObject的实例转换为JSON_Json_Qt_Qvariant - Fatal编程技术网

将QObject的实例转换为JSON

将QObject的实例转换为JSON,json,qt,qvariant,Json,Qt,Qvariant,我用一些代码将任意QObject子类转换为JSON。如果它们是指向子类的指针,我可以转换它们,但我很好奇是否可以转换实例(前提是子类实现了复制构造函数)。是否有一些疯狂的方法可以使用模板或QMetaType提供的类型信息来复制QObject子类的实例,而不知道它是什么?ToJson代码位于一个不知道子类的类中 我认为可以使用QMetaType::create或类似的东西,但我还没有弄清楚如何实际复制子类实例的属性 以下是我的转换代码: QJsonValue ToJson(QVariant val

我用一些代码将任意QObject子类转换为JSON。如果它们是指向子类的指针,我可以转换它们,但我很好奇是否可以转换实例(前提是子类实现了复制构造函数)。是否有一些疯狂的方法可以使用模板或
QMetaType
提供的类型信息来复制
QObject
子类的实例,而不知道它是什么?
ToJson
代码位于一个不知道子类的类中

我认为可以使用
QMetaType::create
或类似的东西,但我还没有弄清楚如何实际复制子类实例的属性

以下是我的转换代码:

QJsonValue ToJson(QVariant value){
    switch(value.type()){
    case QVariant::Int:
    case QVariant::Double:
        return value.toDouble();

    ////Other cases, etc...
    case QVariant::UserType:
        QObject* obj_ptr = qvariant_cast<QObject*>(value);
        if(obj_ptr) // value was originally a pointer to a QObject, works correctly
            return ToJson(obj_ptr);
        else { // value was orginally an instance of a QObject subclass
            std::string t = value.typeName(); //returns "MyQObject"
            int id = QMetaType::type(t.c_str()); //returns the id of the derived class
            void* v = QMetaType::create(id, &value); //passing &value does nothing
            obj_ptr = static_cast<QObject*>(v);
            return ToJson(obj_ptr); //works, but resulting fields are all default 
        }
    }
}

QJsonObject ToJson(QObject* o){
    QJsonObject obj;

    auto mo = o->metaObject();
    for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i){
        QVariant value = o->property(mo->property(i).name());
        obj[mo->property(i).name()] = ToJson(value);
    }
    return obj;
}

有没有办法处理上面
test1
所示的情况

长话短说:不。无法在容器或
QVariant
中按值存储
QObject
s

Qt禁止复制QObject和所有继承类。
Q_OBJECT
宏的强制命令将在新定义的类中禁用任何复制构造函数

MyObject
类中定义的复制构造函数缺少基类构造函数调用。如果
QObject
有一个复制构造函数,它将是这样的:

MyQObject(const MyQObject& other) :
    QObject(other) // this will NEVER compile
{ 
   i = other.i;
   db = other.db;
}
编译器可能会给您一个警告,但允许您使用这样的构造函数,即使每次通过值传递
MyObject
的实例时,它都会导致未定义的行为或切片

此外,缔约国声明如下:

存储在各种容器中的值可以是任何可赋值的 数据类型。要进行限定,类型必须提供默认构造函数 复制构造函数和赋值运算符。这涵盖了大多数数据 您可能希望存储在容器中的类型,包括基本类型 类型(如int和double)、指针类型和Qt数据类型(如 QString、QDate和QTime,但它不包括QObject或任何QObject 子类(QWidget、QDialog、QTimer等)

因此,除非将它们存储为指针,否则不能将
QObject
和派生类存储在Qt容器中,因为QObject的副本被设计禁用


此外,如果您想利用多态行为,就必须使用指针,即使在代码中没有显式需要强制转换到派生类,就我所见。如果你真的需要在某个地方诉诸于铸造,你可以考虑让你的Tojson成为模板函数。p> 有一个解决方案,但请谨慎使用,因为它仅在以下情况下合理/适用:

  • 所讨论的类主要是数据存储类
  • 如果这些类不是从
    QObject
  • 最重要的是,让类从
    QObject
    继承的唯一原因是它可以具有元属性。
如果您的代码将该类用作
QObject
,而不是为了获取元信息,那么如果您试图按值存储该类(正如G.Giordano在其回答中所解释的),则几乎肯定是错误地使用了该类

除了误用注意事项,为了通过值存储
QObject
子类的
QVariant
,您可以使用
QMetaType::create
方法并将用户类型id和
yourQVariant.constData()
传递给它

例如:

MyQObject obj;
obj.db = 11.1;
QVariant value = QVariant::fromValue(obj);

std::string t = value.typeName();
int id = QMetaType::type(t.c_str());
void* v = QMetaType::create(id, value.constData());
obj_ptr = static_cast<QObject*>(v);
QJsonValue json = ToJson(obj_ptr); //json contains db = 11.1
MyQObject对象;
obj.db=11.1;
QVariant value=QVariant::fromValue(obj);
std::string t=value.typeName();
int id=QMetaType::type(t.c_str());
void*v=QMetaType::create(id,value.constData());
obj_ptr=静态铸造(v);
QJsonValue json=ToJson(obj_ptr)//json包含db=11.1

使用map.insert(“myobj”,QVariant::fromValue(&obj))存储并使用
QObject*obj_ptr=qvariant_cast(值)进行检索工作正常。我不想将其强制转换为派生对象,因为转换器不知道派生类。另外,我的问题是,我是否可以处理包含QObject实例而不是指针的映射。由于我的派生对象具有有效的副本构造函数,因此它实际上可以作为实例存储在容器中,但我的
ToJson
函数当前只能处理指针。我将用一个模板版本来搞乱,看看发生了什么。我对我的问题进行了大量编辑,以更好地解释我的意图。感谢您的投入,感谢您的澄清。我再次编辑了我的答案,希望它能有所帮助。我的复制构造函数确实调用了默认的基类构造函数(
QObject()
),但我的示例代码意外地忽略了这一点。为了完整起见,我将添加它
MyQObject(const MyQObject& other) :
    QObject(other) // this will NEVER compile
{ 
   i = other.i;
   db = other.db;
}
MyQObject obj;
obj.db = 11.1;
QVariant value = QVariant::fromValue(obj);

std::string t = value.typeName();
int id = QMetaType::type(t.c_str());
void* v = QMetaType::create(id, value.constData());
obj_ptr = static_cast<QObject*>(v);
QJsonValue json = ToJson(obj_ptr); //json contains db = 11.1