QObject_parent

QObject

构造

构造时如果传入的parent,与当前对象不在同一线程则parent无效,其parent将会变成nullptr。
新建的时候如果传入parent则不需要手动delete。

我们在使用QObject过程中,你们有没有发现没有过传值的情况为什么呢?
因为QObject类声明了Q_DISABLE_COPY,所以QObject和其子类都无法传参或赋值,只能使用的指针或引用进行传递。(究其原因就是其复制过程涉及多线程安全和元对象处理起来较复杂)

class Q_CORE_EXPORT QObject
{
    Q_OBJECT
public:
    explicit QObject(QObject *parent=nullptr);
protected:
    QObject(QObjectPrivate &dd, QObject *parent = nullptr);
private:
    Q_DISABLE_COPY(QObject)
    /* 此宏等同于,删除了拷贝和赋值函数,导致无法进行值传递
       QObject(const QObject &) = delete;
       QObject &operator=(const QObject &) = delete;
    */
}

#define Q_DISABLE_COPY(Class) \
    Class(const Class &) = delete;\
    Class &operator=(const Class &) = delete;

QObject::QObject(QObject *parent)
{
    QObject(*new QObjectPrivate, parent)
}

QObject::QObject(QObjectPrivate &dd, QObject *parent): d_ptr(&dd)
{
    if (parent) {
        //如果父子对象不在同一线程则不能有父子关系,此时parent将被设置为nullptr
        if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() : nullptr, threadData))
                parent = nullptr;
        if (d->isWidget) { //Qwidget类型的走这个分支
            if (parent) {
                d->parent = parent;
                d->parent->d_func()->children.append(this);
            }
        } else {
                setParent(parent);//设置parent
        }
    }
}

析构

设置parent的对象后就不需要我们自己取管理其生命周期,即不需要手动delete,
因为其父对象析构时会自动析构并delete所有子对象。我们只需管理parent生命周期即可

析构时会:

  1. 自动销毁children,并且从父对象中移除它
  2. 析构自动解除所有信号和槽的连接关系
QObject::~QObject()
{
    d->wasDeleted = true;
    d->blockSig = 0; // unblock signals so we always emit destroyed()
     if (!d->isWidget && d->isSignalConnected(0)) {
        emit destroyed(this);//发送destroyed信号
    }
    // 取消所有信号关联的接收者
    for (int signal = -1; signal < receiverCount; ++signal)
     cd->removeConnection(c);
    // 取消所有的槽关联的发送者
    while (QObjectPrivate::Connection *node = cd->senders)
       senderData->removeConnection(node);

    deleteChildren();//析构并删除子对象
    if (d->parent)  
        d->setParent_helper(nullptr);//设置nullptr会先从父对象移除,再设置parent为nullptr
}

void QObjectPrivate::deleteChildren()
{
    Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
    isDeletingChildren = true;
    //遍历删除子对象
    for (int i = 0; i < children.count(); ++i) {
        currentChildBeingDeleted = children.at(i);
        children[i] = 0;
        delete currentChildBeingDeleted;
    }
    children.clear();
    currentChildBeingDeleted = nullptr;
    isDeletingChildren = false;
}

void QObject::setParent(QObject *parent);

此函数设置对象的parent,父子对象必须在同一个线程里面才能设置成功。
流程:

  1. 先从当前父对象移除,并且触发老的父对象QEvent::ChildRemoved
  2. 检查新父对象与当前对象是否同一线程,不在的话直接返回(此时的对象已经没有父亲,其生命周期需要自己管理 )
  3. 在同一线程则添加到新父亲里面,添加成功后触发新父对象QEvent::ChildAdded的事件

取消QObject的父对象,直接设置其parent为nullptr即可,setParent(nullptr);

#QObject的isWidget为false
QObjectPrivate::QObjectPrivate(int version)
    : threadData(nullptr), currentChildBeingDeleted(nullptr)
{
    wasDeleted = false;                         // double-delete catcher
    ......
}

void QObject::setParent(QObject *parent)
{
    Q_D(QObject);
    //isWidget为true时不应该走到QObject的setParent,应该走QWidget的setParent
    Q_ASSERT(!d->isWidget);
    d->setParent_helper(parent);
}

void QObjectPrivate::setParent_helper(QObject *new_parent)
{
    if (new_parent == parent)//如果设置的父亲与当前父亲相同直接返回
        return;
//从当前父对象移除
    QObjectPrivate *parentD = parent->d_func();
    const int index = parentD->children.indexOf(q);
    parentD->children.removeAt(index);
    QChildEvent e(QEvent::ChildRemoved, q);
    QCoreApplication::sendEvent(parent, &e);//发送移除孩子事件给老父亲
//检查是否同一线程
    parent = new_parent;//new_parent设置nullptr,将没有父对象
    if (threadData != parent->d_func()->threadData) 
    {
        //如果新的父亲对象和当前对象不在同一线程无法设置成功。
        //注意此时的对象没有父亲了已经,其声明周期需要自己管理 
        parent = nullptr;
        return;
    }
//添加到新父亲里面
    if(parent){
    parent->d_func()->children.append(q);
    QChildEvent e(QEvent::ChildAdded, q);
    QCoreApplication::sendEvent(parent, &e);//发送添加孩子事件给新父亲
    }
}
   

#QWidget的isWidget为true
QWidgetPrivate::QWidgetPrivate(int version)
{
    ......
     isWidget = true;
}

void QWidget::setParent(QWidget *parent)
{
    if (parent == parentWidget())//如果设置的父亲与当前父亲相同直接返回
        return;
    setParent((QWidget*)parent, windowFlags() & ~Qt::WindowType_Mask);
}

获取parent

QObject *parent() const { return d_ptr->parent; }
此函数用来获取parent,没有父亲则返回nullptr

findChildren

通过对象名称查找符合条件的所有对象,setObjectName可以设置对象名称
QList<myobject > list = obj1->findChildren<myobject>(“”, Qt::FindChildrenRecursively);//所有对象都不会被查到
QList<myobject > list = obj1->findChildren<myobject>();//所有对象都被查到
QList<myobject > list = obj1->findChildren<myobject>(“obj3”, Qt::FindChildrenRecursively);//查到对象名称为obj3的所有对象
Qt::FindChildrenRecursively表示查找所有子对象和子对象递归,默认值
Qt::FindDirectChildrenOnly表示只查找其直接的子对象,不递归查找

    myobject *obj1 = new  myobject("boj1");
    myobject *obj2= new  myobject("boj2");
    myobject *obj3= new  myobject("boj3");
    obj3->setObjectName("obj3");
    obj1->setObjectName("obj1");
    obj2->setObjectName("obj2");
    obj2->setParent(obj1);
    obj3->setParent(obj1);
    ;
    QList<myobject *>  list = obj1->findChildren<myobject*>("obj3",Qt::FindChildrenRecursively);
    if(list.size()>0)
    {
         qDebug()<<list;
    }
    QList<myobject *>  list2 = obj1->findChildren<myobject*>(QRegExp("(obj\\d+)"),Qt::FindChildrenRecursively);
    if(list.size()>0)
    {
         qDebug()<<list2;
    }
    myobject *chird = obj1->findChild<myobject*>("obj3",Qt::FindChildrenRecursively);
    if(chird)
    {
         qDebug()<<chird;
    }

children

const QObjectList &children() const
返回所有子对象列表

findChild

通过对象名称查找符合条件的第一个对象,仅返回一个对象

模板函数
    template<typename T>
    inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
    {
        typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
        return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
    }  

 myobject *chird = obj1->findChild<myobject*>("obj3",Qt::FindChildrenRecursively);
    if(chird)
    {
         qDebug()<<chird;
    }  
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`qobject_cast`是Qt中的一个类型转换宏,用于在QObject继承层次结构中进行安全的类型转换。它用于将一个QObject指针转换为另一个QObject派生类的指针,同时会进行类型检查以确保转换的安全性。 `qobject_cast`的语法如下: ```cpp T qobject_cast<T>(QObject *object); ``` 其中,`T`是目标类型,`object`是要转换的QObject指针。 下面是一个示例,演示了如何使用`qobject_cast`: ```cpp class BaseClass : public QObject { Q_OBJECT public: explicit BaseClass(QObject *parent = nullptr) : QObject(parent) {} }; class DerivedClass : public BaseClass { Q_OBJECT public: explicit DerivedClass(QObject *parent = nullptr) : BaseClass(parent) {} }; int main(int argc, char *argv[]) { QApplication app(argc, argv); BaseClass *baseObj = new DerivedClass(); DerivedClass *derivedObj = qobject_cast<DerivedClass*>(baseObj); if (derivedObj) { // 转换成功 qDebug() << "Type conversion successful"; } else { // 转换失败 qDebug() << "Type conversion failed"; } delete baseObj; return app.exec(); } ``` 在上述示例中,我们定义了一个基类`BaseClass`和一个派生类`DerivedClass`,它们都继承自QObject。在main函数中,我们创建了一个DerivedClass的实例,并将其赋值给一个BaseClass指针。然后,我们使用`qobject_cast`将BaseClass指针转换为DerivedClass指针,并将结果存储在`derivedObj`变量中。 如果转换成功,`derivedObj`将指向DerivedClass的实例,我们可以安全地使用它。如果转换失败,`derivedObj`将为nullptr。 需要注意的是,使用`qobject_cast`进行类型转换的前提是相关的类必须在QObject继承层次结构中,并且必须使用了Q_OBJECT宏来启用Qt元对象系统的支持。否则,转换将失败并返回nullptr。 此外,`qobject_cast`还可以用于在信号槽连接中进行类型安全检查,以确保连接的正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值