我项目的公共部分(crating lib)目前拥有一个类型为的接口Class:
class CanBeAddedToGroup{
public:
void addToGroup(Group& )=0;
}
现在我还想在包含QVariant数据的Class上使用该程序,所以我开始简单:
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>
}
}
};
}
现在添加到列表中的一个数据类型(在lib之外)属于以下类型:
class DataClass: public QObject, public CanBeAddedToGroup{
void addToGroup(Group& );
}
Q_DECLARE_METATYPE(DataClass)
使用“QVariant :: fromValue”将它添加到地图中,现在我需要在“DataContainingClass”中检查数据是否来自QObject,所以我知道static_cast(variant.data() ) 已验证。 然后我可以尝试dynamic_cast对象指向CanBeAddedToGroup,并调用它。
---编辑---: 问题不是:拥有一个QObject并检查它是否继承了另一个QObject,它甚至不检查一个Class是否继承了另一个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&amp; 4(“schouldSegFault”),而不使用仅在lib之外定义的东西。
我已经尝试过:
int tst4 = qRegisterMetaType<CanClass>("CanClass");
QMetaType help2(tst4);
但是help2的MetaObject为0,所以我无法检查QObject的继承。
编辑/为谁添加了“Proper way to check QObject derived class type in Qt”在我的程序中问题是该类继承自另一个QObject
类,所以我无法查询我的接口的继承(即使定义为Q_Gadget)使用继承,因为它只适用于第一个元素。
PS:对于每个试图在包含Object而不是指针的QVariant上调用函数的人都可能对这种方法感兴趣: How to support comparisons for QVariant objects containing a custom type? / https://pastebin.com/tNLa0jSa
虽然拥有类型的全球注册表是我希望我能避免的情况。
答案 0 :(得分:2)
只需尝试使用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
重要部分:
QObject
,并且具有Q_OBJECT
宏。QVariant::value()
并尝试将包含的值转换为目标类。在示例中,我使用QVariant::value<MyQObjectClass*>()
- 根据文档,如果值可以转换为它,则返回包含的MyQObjectClass*
实例,如果QVariant
,则返回包含基本值或小工具 - 默认构造值。在指针的情况下,这将是一个空指针,因此只需检查返回的值是否为null。那就是它。永远不要直接使用Qvariant::data()
。
<强>更新强>
正如一句话:Qobject
类将复制构造函数和赋值运算符声明为私有:
QObject既没有复制构造函数也没有赋值运算符。这是设计的。实际上,它们是声明的,但是在具有宏Q_DISABLE_COPY()的私有部分中。实际上,从QObject(直接或间接)派生的所有Qt类都使用此宏来声明其复制构造函数和赋值运算符是私有的。推理可以在Qt对象模型页面上关于Identity vs Value的讨论中找到。
因此,您无法复制QObject
的实例(因此您无法将其存储在QVariant
中)。相反,您将指针传递给QObject
个实例。
更新#2
如果您的界面类无法直接从QObject
派生,则可以考虑使用Qt's plugin mechanism。以上示例略微编辑以适应此方法:
#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有关接口部分。QObject*
转换为QVariant::value()
。如果成功,您可以尝试qobject_cast
到您的接口类。答案 1 :(得分:0)
您的设计完全被破坏:QObject
s不能用作无限制值。它们不能被复制或移动,并且你的复制构造函数的实现隐藏了这个基本事实。