使用 Qt 的元对象系统获取对象实例类名

Posted

技术标签:

【中文标题】使用 Qt 的元对象系统获取对象实例类名【英文标题】:Get object instance class name with Qt's meta-object system 【发布时间】:2020-11-05 13:56:11 【问题描述】:

我有 3 个课程:

class Being : public QObject 
    Q_OBJECT
public:
    explicit Being(QObject *parent = nullptr);
;

class Animal : public Being 
    Q_OBJECT
public:
    explicit Animal(QObject *parent = nullptr);
;

class Dog : public Animal 
    Q_OBJECT
public:
    explicit Dog(QObject *parent = nullptr);
;

Being的实现如下:

Being::Being(QObject *parent) : QObject(parent) 
    qDebug() << staticMetaObject.className();

我有以下代码:

Being *pBeing = new Being();
Being *pAnimal = new Animal();
Being *pDog = new Dog();

问题是:有没有办法实现Being的构造函数,这样我就可以访问指向我的Being基类的实际实例,这样上面代码的日志就会是:

Being
Animal
Dog

?

编辑: 我的意图是我希望能够在 Being 基类中处理 Animal.txtBeing.txtDoc.txt。而且我需要知道,根据实例的类型,我是否需要解析Animal.txtBeing.txtDoc.txt 以获取更多信息。

Qt 支持这个吗?有没有一种机制我可以使用 C++/Qt 来实现这一点?如果没有,是否有任何优雅的折衷解决方案?

【问题讨论】:

在 Being::Being 构造函数中你绝对需要这个吗?一旦构造了对象,您就可以引用元对象,但这在那时是不可能的(封闭对象尚未完全构造) 不一定在构造函数中,但我需要一种机制来知道,在我的 Being 类中,实例的类型为 BeingAnimalDog... 如果这是为了调试,那就是metaObject-&gt;className()。如果您打算在类名上调度,请改用多态性。 不,这不仅仅是为了调试,请参阅我的编辑。我的自动机制会根据所使用的实例类型收集更多信息。 【参考方案1】:

Being 的构造函数中是不可能的,因为尚未构造封闭对象,因此有关它的元数据不可用。但是,您可以编写应该​​在对象构造之后调用的 initialize 方法,例如带打印功能:

class Being : public QObject 
    Q_OBJECT
public:
    explicit Being(QObject *parent = nullptr)  qDebug() << this->metaObject()->className();   // this will always print "Being"
    void initialize()  qDebug() << this->metaObject()->className();   // this will print the actual class name
;

class Animal : public Being 
    Q_OBJECT
public:
    explicit Animal(QObject *parent = nullptr)  initialize();   // you can already use this method in the constructor
;

TEST(xxx, yyy)

    Being* being = new Being();
    Being* animal = new Animal();
    being->initialize();
    animal->initialize();  // or you can call it later

如果initialize 方法不是很好的解决方案,您可以随时通过Being 构造函数:explicit Being(QString name, QObject* parent = nullptr; 然后explicit Animal(QObject *parent = nullptr): Being("Animal") 破解它,但我认为它不太优雅。

【讨论】:

【参考方案2】:

我的意图是我希望能够拥有将在 Being 基类中处理的 Animal.txt、Being.txt 和 Doc.txt。而且我需要知道,根据实例的类型,我是否需要解析 Animal.txt、Being.txt 或 Doc.txt 以获取更多信息。

永远不要让基类知道它的子类。永远。

无论它看起来多么诱人,都不要这样做(即使你知道怎么做)。

一个类可能有数百个子类。以QObject 为例。 QObject 是否应该(或者可能)知道您对 QMainWindow 的重新实现?

所以,无论做出这个设计决定的原因是什么,改变它!

可能的解决方案

如果文本文件的处理算法相同,无论子类如何,创建一个基类方法进行处理,并从子类中调用。

如果算法依赖于子类,将方法抽象化,即virtual,不带实现(=0),让实现到子类。

【讨论】:

以上是关于使用 Qt 的元对象系统获取对象实例类名的主要内容,如果未能解决你的问题,请参考以下文章

QT:获取对象的类名

Qt5只反射机制(内省)

Qt笔记——元对象系统

Qt教程 : Qt元对象系统

QT软件开发之入门基础--1.8元对象系统

C# 利用反射根据类名创建类的实例对象