• Qt之qobject_cast实现


    使用背景

    qobject_cast与C++提供的static_cast、dynamic_cast类似,用于实现类的动态转换。

    /*qobject_cast函数*/
    DestType* qobject_cast<DestType*>(QObject *p);
    
    • 1
    • 2

    使用该函数有两个前提条件:

    1. 需要转换的类需要继承自QObject
    2. 类需要声明Q_OBJECT宏

    qobject_cast()函数的行为类似于标准c++ dynamic_cast(),其优点是它不需要RTTI支持,并且可以跨动态库边界工作。它试图将其实参强制转换为尖括号中指定的指针类型,如果对象的类型正确(在运行时确定),则返回一个非零指针,如果对象的类型不兼容则返回0。

    实现原理

    Q_OBJECT宏

    #define Q_OBJECT \
    public: \
        QT_WARNING_PUSH \
        Q_OBJECT_NO_OVERRIDE_WARNING \
        static const QMetaObject staticMetaObject; \
        virtual const QMetaObject *metaObject() const; \
        virtual void *qt_metacast(const char *); \
        virtual int qt_metacall(QMetaObject::Call, int, void **); \
        QT_TR_FUNCTIONS \
    private: \
        Q_OBJECT_NO_ATTRIBUTES_WARNING \
        Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
        QT_WARNING_POP \
        struct QPrivateSignal {}; \
        QT_ANNOTATE_CLASS(qt_qobject, "")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Q_OBJECT宏所代指的代码如上所示,其中在所有启用Q_OBJECT宏的类中都新建了一个静态的QMetaObject实例staticMetaObject
    qmake对包含Q_OBJECT宏的文件会生成一个moc文件,moc文件中对staticMetaObject的初始化代码如下。

    QT_INIT_METAOBJECT const QMetaObject MyDialog::staticMetaObject = { {
    	//这里将父类的staticMetaObject对象指针存入当前类superdata形成继承树
        QMetaObject::SuperData::link<QDialog::staticMetaObject>(),
        qt_meta_stringdata_MyDialog.data,
        qt_meta_data_MyDialog,
        qt_static_metacall,
        nullptr,
        nullptr
    } };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    qobject_cast函数

    template <class T>
    inline T qobject_cast(QObject *object)
    {
    	//获取输入模板类
        typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
        Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
                        "qobject_cast requires the type to have a Q_OBJECT macro");
        //通过调用模板类的静态成员变量的cast函数,函数的传入参数为需要转换的指针
        return static_cast<T>(ObjType::staticMetaObject.cast(object));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    下面是QMetaObject类的cast函数

    QObject *QMetaObject::cast(QObject *obj) const
    {
        // ### Qt 6: inline
        return const_cast<QObject*>(cast(const_cast<const QObject*>(obj)));
    }
    
    const QObject *QMetaObject::cast(const QObject *obj) const
    {
    	//判断传入的指针是否继承自模板类 
    	//如果是则传出obj 进行static_cast是安全的
    	//如果不是传出nullptr 
    	//因此qobject_cast相当于dynamic_cast,是一个安全的转型函数
        return (obj && obj->metaObject()->inherits(this)) ? obj : nullptr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    bool QMetaObject::inherits(const QMetaObject *metaObject) const noexcept
    {
    	//这里this指针指向的为之前传入模板类的staticMetaObject
        const QMetaObject *m = this;
        //对输入mentaObject的继承树向前查找,判断是否存在与传入模板类相同的staticMetaObject
        //若存在则证明输入类继承自模板类
       	//d.superdata是在moc文件中完成初始化的
        do {
            if (metaObject == m)
                return true;
        } while ((m = m->d.superdata));
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    总结

    1. qobject_cast使用需要满足:①继承自QOBject类 ②启用Q_OBJECT宏
    2. qobject_cast为安全的转型函数,其效率比dynamic_cast要高
  • 相关阅读:
    oracle报错 ORA-02290: 违反检查约束条件问题
    ModifyAjaxResponse,修改ajax请求返回值,前后端调试之利器
    使用 Helm 管理应用的一些 Tips
    ARM器件和DSP器件的区别
    [附源码]计算机毕业设计基于Springboot三星小区车辆登记系统
    优化理论06-----非线性共轭梯度法: HS、FR-CG、PR-CG、PR+-CG
    ubuntu配置cuda环境
    操作系统:处理机调度与死锁 练习题
    TeamTalk中对一条连接收发消息的封装。
    Radware Alteon负载均衡-基于域名的七层负载均衡
  • 原文地址:https://blog.csdn.net/Devout_programming/article/details/126310359