Q调用在项目主要部分定义的存储对象的函数



我的项目的公共部分(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

重要部分:

  1. 确保要存储在 QVariant 中的类派生自QObject并具有Q_OBJECT宏。
  2. 循环访问映射时,请使用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"

您需要:

  1. 定义接口类并使用Q_DECLARE_INTERFACE宏将其注册到Qt。
  2. 声明从QObject和接口类派生的具体类。此外,您需要使用Q_INTERFACES宏告诉 Qt 有关接口部分的信息。
  3. 检查地图中的值时,首先尝试通过QVariant::value()转换为QObject*。如果此操作成功,则可以尝试qobject_cast接口类。

你的设计完全被破坏了:QObject不能用作不受限制的值。它们不能被复制或移动,并且复制构造函数的实现隐藏了这个基本事实。

相关内容

  • 没有找到相关文章

最新更新