设计模式:可复用面向对象软件及基础:3-3 结构型模式:组合模式(composite)_~怎么回事啊~的博客-CSDN博客
qt d指针和对象树_~怎么回事啊~的博客-CSDN博客
从数据层看:组合模式/整体-部分模式
QObject组合模式 从UI层看也可以称为:句柄-实体模式
1 QObject是唯一的句柄基类,d_ptr指向实体(数据)类
2 QObjectData 是唯一的实体(数据)基类,q_ptr指向实体对象对应的QObject(句柄类)
3 q_ptr(接口类/句柄基类)和d_ptr指针(实体/数据类)使得句柄和实体可以双向引用
4 q_ptr = q_func() 获取数据类 / d_ptr = d_fun 获取接口类
QObject 中有 QScopedPointer
并且在构造函数中,创建了 QObjectPrivate ,并且让d_prt的q_ptr 指向自己,QObjectPrivate继承于QObjectData
QObjectData是所有数据类的唯一基类,它里面存储了q_ptr,children(子对象列表)
class Q_CORE_EXPORT QObjectData {
public:
virtual ~QObjectData() = 0;
QObject *q_ptr;
QObject *parent;
QObjectList children;
uint isWidget : 1;
uint blockSig : 1;
uint wasDeleted : 1;
uint isDeletingChildren : 1;
uint sendChildEvents : 1;
uint receiveChildEvents : 1;
uint isWindow : 1; //for QWindow
uint deleteLaterCalled : 1;
uint unused : 24;
int postedEvents;
QDynamicMetaObjectData *metaObject;
QMetaObject *dynamicMetaObject() const;
};
任何继承自QObject的派生对象都可以看作是一个QObject对象,可以使用信号与槽与其他QObject对象通信
每一个QObject对象只能有一个父类QObject对象和任意数量的子类QObject对象,每个QObject对象都有一个QObjectList存放子对象列表
1 子对象列表的作用:为父类和子类建立了一个双向联系,父对象知道子对象的地址,子对象也知道父对象的地址,
每个父对象都会管理自己的子对象,在父对象析构时会自动释放其所关联的子对象
管理:
1 获取子对象列表children()
inline const QObjectList &children() const { return d_ptr->children; }
typedef QList QObjectList; 孩子对象用链表存储,方便频繁的删除和添加
2 查找指定子对象列表 findChildren()
template
inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{
typedef typename std::remove_cv::type>::type ObjType;
return static_cast(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
}
// 通过name 查找特定的孩子
QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options)
{
if (!parent)
return 0;
const QObjectList &children = parent->children();
QObject *obj;
int i;
for (i = 0; i < children.size(); ++i) {
obj = children.at(i);
if (mo.cast(obj) && (name.isNull() || obj->objectName() == name))
return obj;
}
if (options & Qt::FindChildrenRecursively) {
for (i = 0; i < children.size(); ++i) {
obj = qt_qFindChild_helper(children.at(i), name, mo, options);
if (obj)
return obj;
}
}
return 0;
}
3 销毁孩子结点 通过析构函数:QObject析构函数
销毁对象,删除其所有子对象。所有进出对象的信号都会自动断开,并且对象的任何未决发布事件都将从事件中删除队列。但是,使用 deleteLater() 通常比使用直接删除 QObject 子类更加安全。
QObject::~QObject()
{
Q_D(QObject);
d->wasDeleted = true;
d->blockSig = 0; // unblock signals so we always emit destroyed()
......
// 1 删除孩子结点
if (!d->children.isEmpty())
d->deleteChildren();
#if QT_VERSION < 0x60000
qt_removeObject(this);
#endif
if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
reinterpret_cast(qtHookData[QHooks::RemoveQObject])(this);
// 将自己的从父结点中移除
if (d->parent) // remove it from parent object
d->setParent_helper(0);
}
void QObjectPrivate::deleteChildren()
{
Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
isDeletingChildren = true;
// delete children objects
// don't use qDeleteAll as the destructor of the child might
// delete siblings
//遍历孩子结点
for (int i = 0; i < children.count(); ++i) {
currentChildBeingDeleted = children.at(i);
children[i] = 0;
delete currentChildBeingDeleted;//删除孩子结点指针 为了调用孩子结点的析构函数,从而递归删除孩子结点
}
children.clear();
currentChildBeingDeleted = 0;
isDeletingChildren = false;
}
重新设定子对象的父对象
要求:子对象和父对象必须在同线程
自定义类qttest 在构造函数中
调用QWiget的构造:
因为QWidget 继承QObject ,因此调用 QObject的构造函数:因此,在qttest类中,最终d_ptr指向QWidgetPrivate类
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
Q_D(QObject);
d_ptr->q_ptr = this;
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
d->threadData->ref();
if (parent) {
QT_TRY {
//判断父子对象是否在同一个线程中
if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData))
parent = 0;
if (d->isWidget) {
if (parent) {
d->parent = parent;
d->parent->d_func()->children.append(this);
}
// no events sent here, this is done at the end of the QWidget constructor
} else {
setParent(parent);
}
} QT_CATCH(...) {
d->threadData->deref();
QT_RETHROW;
}
}
#if QT_VERSION < 0x60000
qt_addObject(this);
#endif
if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
reinterpret_cast(qtHookData[QHooks::AddQObject])(this);
}
使用:void QObject::setParent(QObject *parent)
/*!
Makes the object a child of \a parent.
\sa parent(), children()
*/
void QObject::setParent(QObject *parent)
{
Q_D(QObject);
Q_ASSERT(!d->isWidget);
d->setParent_helper(parent);
}
void QObjectPrivate::setParent_helper(QObject *o)
{
Q_Q(QObject);
if (o == parent)
return;
if (parent) {
QObjectPrivate *parentD = parent->d_func();
if (parentD->isDeletingChildren && wasDeleted
&& parentD->currentChildBeingDeleted == q) {
// don't do anything since QObjectPrivate::deleteChildren() already
// cleared our entry in parentD->children.
} else {
//从之前的父对象的孩子列表删除该对象
const int index = parentD->children.indexOf(q);
if (parentD->isDeletingChildren) {
parentD->children[index] = 0;
} else {
parentD->children.removeAt(index);
if (sendChildEvents && parentD->receiveChildEvents) {
QChildEvent e(QEvent::ChildRemoved, q);
QCoreApplication::sendEvent(parent, &e);
}
}
}
}
parent = o;
if (parent) {
// object hierarchies are constrained to a single thread
if (threadData != parent->d_func()->threadData) {
qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");
parent = 0;
return;
}
//将新的父类孩子列表中添加该对象
parent->d_func()->children.append(q);
if(sendChildEvents && parent->d_func()->receiveChildEvents) {
if (!isWidget) {
QChildEvent e(QEvent::ChildAdded, q);
QCoreApplication::sendEvent(parent, &e);
}
}
}
if (!wasDeleted && !isDeletingChildren && declarativeData && QAbstractDeclarativeData::parentChanged)
QAbstractDeclarativeData::parentChanged(declarativeData, q, o);
}
没有父对象的在栈区创建,位于栈区对象在超出作用域时被销毁,子对象也随之被销毁
有父对象的在堆区创建
当我们创建了一个对象,并且指定父对象时,内部做了哪些处理呢?
调用QPushButton的构造函数,
QPushButton::QPushButton(QWidget *parent)
: QAbstractButton(*new QPushButtonPrivate, parent)
{
Q_D(QPushButton);
d->init();
}
调用QAbstractButton的构造函数
/*! \internal
*/
QAbstractButton::QAbstractButton(QAbstractButtonPrivate &dd, QWidget *parent)
: QWidget(dd, parent, 0)
{
Q_D(QAbstractButton);
d->init();
}
调用QWidget的构造函数
QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f)
: QObject(dd, 0), QPaintDevice()
{
Q_D(QWidget);
QT_TRY {
d->init(parent, f);
} QT_CATCH(...) {
QWidgetExceptionCleaner::cleanup(this, d_func());
QT_RETHROW;
}
}
调用QObject的构造函数,将d_ptr赋值dd,d向上追溯是QPushButtonPrivate;但是由于传递的是QObject(dd,0);也就是parent在QObject的构造函数中是空的,因此不会走到下面的if (parent)中
/*!
\internal
*/
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
Q_D(QObject);
d_ptr->q_ptr = this;
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
d->threadData->ref();
if (parent) {
QT_TRY {
if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData))
parent = 0;
if (d->isWidget) {
if (parent) {
d->parent = parent;
d->parent->d_func()->children.append(this);
}
// no events sent here, this is done at the end of the QWidget constructor
} else {
setParent(parent);
}
} QT_CATCH(...) {
d->threadData->deref();
QT_RETHROW;
}
}
#if QT_VERSION < 0x60000
qt_addObject(this);
#endif
if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
reinterpret_cast(qtHookData[QHooks::AddQObject])(this);
}
真正设置父子关系的地方在:
继续看 void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) 这个函数:
void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
{
...
else if (parentWidget)
q->setParent(parentWidget, data.window_flags);
...
}
最终调用到 QObjectPrivate::setParent_helper(QObject *o) 这个函数完成将该对象添加到父对象的孩子链表中;
复合对象:复合对象通常将两个或多个现有对象组合成单个对象
组合对象:组合对象是要将多个元素作为一个对象来处理,需要将它们组合
QObjectData 数据封装
QObjectPriavte封装的是线程和具体信号的处理