我的项目的公共部分(crating a lib(当前包含一个接口类类型:
class CanBeAddedToGroup{
public:
void addToGroup(Group& )=0;
}
现在我还想在包含 QVariant 中的数据的类上使用该程序,所以我开始很简单:
class DataContainingClass: public CanBeAddedToGroup{
QMap<QString,QVarient> data;
public:
void addToGroup(Group& ){
QMap<QString,QVarient>::itterator itter = data.begin();
QMap<QString,QVarient>::itterator end= data.end();
for(;itter !=end;itter ++){
<Handle Data>
}
}
};
}
现在添加到列表(在库外部(的数据类型之一为:
class DataClass: public QObject, public CanBeAddedToGroup{
void addToGroup(Group& );
}
Q_DECLARE_METATYPE(DataClass)
它使用"QVariant::fromValue("添加到地图中,现在我需要在"DataContainingClass"中检查数据是否来自QObject,所以我知道static_cast(variant.data(((是有效的。 然后我可以尝试将对象指针dynamic_cast到 CanBeAddToGroup,并调用它。
---编辑---: 问题不在于:拥有一个 QObject 并检查它是否继承了另一个 QObject,它甚至不是检查一个类是否继承自另一个类,而是要知道我拥有的数据是否真的是 QObject。
最小示例: 头文件:
#include <QObject>
#include <QDebug>
class DmbClass: public QObject{
Q_OBJECT
public:
DmbClass(){TST="RealOne";}
DmbClass(const DmbClass&d){TST="Clone";}
QString TST;
};
Q_DECLARE_METATYPE(DmbClass)
class Tst{
public:
virtual void tstFunct()=0;
};
class CanClass: public QObject, public Tst{
Q_OBJECT
public:
CanClass(){TST="RealOne";}
CanClass(const CanClass&d){TST="Clone";}
QString TST;
virtual void tstFunct() override{
qDebug()<<"tst";
}
};
Q_DECLARE_METATYPE(CanClass)
class DmbGadget{
Q_GADGET
public:
DmbGadget(){TST="RealOne";}
DmbGadget(const DmbGadget&d){TST="Clone";}
QString TST;
};
Q_DECLARE_METATYPE(DmbGadget)
C 文件:
// QObject in QVariant
DmbClass dC;
QVariant varC=QVariant::fromValue(dC);
const void* vPC = varC.data();
DmbClass dCc = varC.value<DmbClass>();
QObject* objC = (QObject*)varC.data();
QObject* schouldWork = objC->parent();
Tst* schouldBeNull = dynamic_cast<Tst*>(objC);
// Object using correct base class in QVariant
CanClass dT;
QVariant varT=QVariant::fromValue(dT);
const void* vPT = varT.data();
CanClass dTc = varC.value<CanClass>();
QObject* objT = (QObject*)varT.data();
QObject* schouldWork2 = objT->parent();
Tst* schouldNotNull = dynamic_cast<Tst*>(objT);
schouldNotNull->tstFunct();
// Q_Gadget in QVariant
DmbGadget dG;
QVariant varG=QVariant::fromValue(dG);
const void* vPG = varG.data();
DmbGadget dGg = varG.value<DmbGadget>();
QObject* objD = (QObject*)varG.data();
//QObject* schouldSegFault = objD->parent();
// base value in QVariant
QVariant var4=4;
const void* vP4 = var4.data();
QObject* obj4 = (QObject*)var4.data();
//QObject* schouldSegFault2 = obj4 ->parent();
我需要一种方法来区分案例 1 和 2 从 3 和 4("schouldSegFault"(,而不使用仅在库之外定义的东西。
我已经尝试过:
int tst4 = qRegisterMetaType<CanClass>("CanClass");
QMetaType help2(tst4);
但是 help2 的元对象为 0,所以我无法检查 QObject 的固有性。
编辑/对于谁添加了"在 Qt 中检查 QObject 派生类类型的正确方法",这是我的程序中的问题,该类继承自另一个QObject
类,所以我不能使用继承来考虑我的接口的固有性(即使定义为 Q_Gadget(,因为它只适用于第一个元素。
PS:对于每个试图在包含对象而不是指针的 QVariant 上调用函数的人都可能对这种方法感兴趣: 如何支持包含自定义类型的 QVariant 对象的比较?/https://pastebin.com/tNLa0jSa
虽然拥有类型的全局注册表是我希望我可以避免这种情况的。
只需尝试使用 QVariant::value 并查看QVariant
中的值是否可以转换为您的目标类。下面是一个最小示例:
#include <QObject>
#include <QVariant>
#include <QVariantMap>
#include <QDebug>
class MyQObjectClass : public QObject {
Q_OBJECT
public:
explicit MyQObjectClass(QObject *parent = nullptr) : QObject(parent) {}
void greet() { qDebug() << "I am a MyQObjectClass!"; }
};
Q_DECLARE_METATYPE(MyQObjectClass*)
int main(int, char *[])
{
MyQObjectClass obj;
QVariantMap map;
map.insert("foo", QString("Hello World"));
map.insert("bar", QVariant::fromValue(&obj));
QVariantMap::iterator iter = map.begin();
QVariantMap::iterator end= map.end();
for(;iter !=end;iter ++) {
auto value = iter.value();
// Try to convert to MyQObjectClass*
auto obj = value.value<MyQObjectClass*>();
if (obj != nullptr) {
qDebug() << iter.key() << "is an instance of MyQObjectClass";
obj->greet();
continue;
}
qDebug() << iter.key() << "is not an instance of MyQObjectClass";
}
}
#include "main.moc"
运行它应该在控制台上产生以下输出:
"bar" is an instance of MyQObjectClass
I am a MyQObjectClass!
"foo" is not an instance of MyQObjectClass
重要部分:
- 确保要存储在 QVariant 中的类派生自
QObject
并具有Q_OBJECT
宏。 - 循环访问映射时,请使用
QVariant::value()
并尝试将包含的值转换为目标类。在示例中,我使用QVariant::value<MyQObjectClass*>()
- 根据文档,如果值可以转换为它,则返回包含的MyQObjectClass*
实例,或者 - 如果QVariant
包含基本值或小工具,则返回默认构造值。在指针的情况下,这将是一个空指针,所以只需检查返回的值是否为 null。就是这样。
永远不要直接处理Qvariant::data()
。
更新
正如评论:Qobject
类将复制构造函数和赋值运算符声明为私有:
来自官方文档:
QObject既没有复制构造函数,也没有赋值运算符。这是设计使然。实际上,它们是声明的,但是在带有宏 Q_DISABLE_COPY(( 的私有部分中。事实上,所有派生自 QObject(直接或间接(的 Qt 类都使用此宏来声明它们的复制构造函数和赋值运算符是私有的。推理可以在Qt对象模型页面上关于身份与价值的讨论中找到。
因此,您无法复制QObject
实例(因此您无法将它们存储在QVariant
中(。相反,您将指针传递到QObject
实例。
更新 #2
如果你的接口类不能直接从QObject
派生,你可以考虑使用Qt的插件机制。下面是上面经过稍微编辑以适应这种方法的示例:
#include <QObject>
#include <QVariant>
#include <QVariantMap>
#include <QDebug>
class MyInterfaceClass {
public:
MyInterfaceClass() {}
virtual ~MyInterfaceClass() {}
virtual void greet() = 0;
};
#define MyInterfaceClass_IID "org.example.MyInterfaceClass"
Q_DECLARE_INTERFACE(MyInterfaceClass, MyInterfaceClass_IID)
class MyConcreteClass : public QObject, public MyInterfaceClass {
Q_OBJECT
Q_INTERFACES(MyInterfaceClass)
public:
MyConcreteClass(QObject *parent = nullptr) : QObject(parent) {}
void greet() override { qDebug() << "I am a MyInterfaceClass!"; }
};
int main(int, char *[])
{
MyConcreteClass obj;
QVariantMap map;
map.insert("foo", QString("Hello World"));
map.insert("bar", QVariant::fromValue(&obj));
QVariantMap::iterator iter = map.begin();
QVariantMap::iterator end= map.end();
for(;iter !=end;iter ++) {
auto value = iter.value();
// Try to convert to QObject*:
auto obj = value.value<QObject*>();
if (obj != nullptr) {
// Try if we can cast to our interface class:
auto ifc = qobject_cast<MyInterfaceClass*>(obj);
if (ifc != nullptr) {
qDebug() << iter.key() << "is an instance of MyInterfaceClass";
ifc->greet();
}
continue;
}
qDebug() << iter.key() << "is not an instance of MyInterfaceClass";
}
}
#include "main.moc"
您需要:
- 定义接口类并使用
Q_DECLARE_INTERFACE
宏将其注册到Qt。 - 声明从
QObject
和接口类派生的具体类。此外,您需要使用Q_INTERFACES
宏告诉 Qt 有关接口部分的信息。 - 检查地图中的值时,首先尝试通过
QVariant::value()
转换为QObject*
。如果此操作成功,则可以尝试qobject_cast
接口类。
你的设计完全被破坏了:QObject
不能用作不受限制的值。它们不能被复制或移动,并且复制构造函数的实现隐藏了这个基本事实。