Qt之qobject_cast实现

使用背景

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

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

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

  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, "")

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
} };

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));
}

下面是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;
}
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. qobject_cast使用需要满足:①继承自QOBject类 ②启用Q_OBJECT宏
  2. qobject_cast为安全的转型函数,其效率比dynamic_cast要高
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值