我有一些代码用于将任意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;
}
示例代码用例:
qRegisterMetaType<MyQObject>();
MyQObject obj;
obj.db = 11.1;
QVariant test1 = QVariant::fromValue(obj);
QVariant test2 = QVariant::fromValue(&obj);
QJsonValue v1 = ToJson(test1); // default constructed values
QJsonValue v2 = ToJson(test2); // db = 11.1
示例QObject子类:
class MyQObject : public QObject {
Q_OBJECT
Q_PROPERTY(double DB MEMBER db)
Q_PROPERTY(int I MEMBER i)
public:
MyQObject();
MyQObject(const MyQObject& other) : QObject() {
i = other.i;
db = other.db;
}
int i = 50;
double db = 1.5;
};
Q_DECLARE_METATYPE(MyQObject)
有没有办法处理上面test1
所示的案例?
答案 0 :(得分:0)
长话短说:不。无法按容器或QObject
按值存储QVariant
。
Qt禁止QObjects和所有继承类的副本。强制Q_OBJECT
宏也将在新定义的类中禁用任何复制构造函数。
您在MyObject
类中定义的复制构造函数缺少基类构造函数调用。如果QObject
有一个复制构造函数,它将是这样的:
MyQObject(const MyQObject& other) :
QObject(other) // this will NEVER compile
{
i = other.i;
db = other.db;
}
编译器可能会给你一个警告,但允许你有这样的构造函数,即使它会导致未定义的行为,或者切片每次MyObject
的实例按值传递。
此外,Qt docs声明如下:
存储在各种容器中的值可以是任何可分配的 数据类型。要限定,类型必须提供默认构造函数,a 复制构造函数和赋值运算符。这涵盖了大多数数据 您可能希望存储在容器中的类型,包括基本类型 类型,如int和double,指针类型和Qt数据类型,如 QString,QDate和QTime,但它不包括QObject或任何QObject 子类(QWidget,QDialog,QTimer等)。
因此,您不能将QObject
和派生类存储在Qt容器中,除非您将它们存储为指针,因为QObject的副本已被设计禁用。
此外,如果你想利用多态行为,你必须使用指针,即使我没有明确需要在你的代码中强制转换为派生类。如果你真的需要在某个地方求助,你可以考虑让你的ToJson成为模板功能。
答案 1 :(得分:0)
有一个解决方案,但请谨慎使用,因为它只适用于以下情况:
QObject
QObject
的唯一理由是它可以具有元属性。 如果您的代码因为获取元信息之外的任何原因而将该类用作QObject
,那么如果您尝试按值存储它,则几乎肯定会错误地使用它(如G. Giordano所述)他们的回答)。
除了滥用注意事项之外,为了JSON-ify QVariant
按值存储QObject
子类,您可以使用QMetaType::create
方法并将其传递给用户类型ID和{ {1}}。
示例:
yourQVariant.constData()