QT Source Analysis Qobject (from CSDN, author Oowgsoo)

Source: Internet
Author: User

1. Test code:

#include <QApplication>
#include <QtCore>
#include <QtGui>

int main (int argc, char *argv[])
{
Qapplication app (argc, argv);

int size = sizeof (qobject);

qpushbutton* quit = new Qpushbutton ("Quit");
Delete quit;

return App.exec ();
}

Qobject is the only base class of the QT class system, like MFC in the CObject and Dephi in the TObject, is the QT various functions Fountainhead, so the first section of QT source analysis is placed on this qobject

int size = sizeof (qobject);

The size of the Qobject is 8, except for the 4 bytes required by the virtual function table pointer, and the other 4 bytes are:
Qobjectdata *d_ptr;
The data in the Qobject is encapsulated in the Qobjectdata class, why encapsulate the data?
The reason is that there is a very important design pattern in QT is the handle entity pattern, that is, the class with Qobject as the base class is generally a handle class, usually only a pointer to an entity class, in the entity class to save all the data
And in general, this pointer is still private, it is convenient to modify the implementation details of the handle class later
Therefore, it is also possible to say and the handle class inheritance relationship parallel also a set of entity class derivation system, so, to be exact, QT's base class actually has two, one is the Qobject, this is the handle class the unique base class, the other is the qobjectdata, this is the entity
Base class for Class

The Qobjectdata class is defined as follows:

Class Qobjectdata {
Public
Virtual ~qobjectdata () = 0;
Qobject *q_ptr;
Qobject *parent;
Qobjectlist children;

UINT Iswidget:1;
UINT Pendtimer:1;
UINT Blocksig:1;
UINT Wasdeleted:1;
UINT Ownobjectname:1;
UINT Sendchildevents:1;
UINT Receivechildevents:1;
UINT Unused:25;
int postedevents;
#ifdef Qt3_support
int postedchildinsertedevents;
#else
int reserved;
#endif
};

Qobject *q_ptr;
This pointer points to the corresponding handle class for the entity class, and the code above
Qobjectdata *d_ptr;
Echo, so that the handle class and the entity class can be two-way reference, why is such a naming method? Maybe Q refers to the Qt interface class, d refers to the data class, which of course is guessing, but it may be convenient for you to remember, in Qt,
The names of these two pointers are very important and must be remembered

But it is still not easy to use these two pointers, because they are all types of base classes, do you want to type conversion for each use? For the sake of simplicity, QT declares two macros here

#define Q_DECLARE_PRIVATE (Class)/
Inline class# #Private * D_func () {return reinterpret_cast<class# #Private *> (d_ptr);}/
inline Const class# #Private * D_FUNC () const {return reinterpret_cast<const class# #Private *> (d_ptr);}
Friend class class# #Private;

#define Q_DECLARE_PUBLIC (Class)/
Inline class* Q_func () {return static_cast<class *> (q_ptr);}/
Inline const class* Q_func () const {return static_cast<const Class *> (q_ptr);}/
Friend Class class;

As long as the two macros are used in the header file of the class, the actual type of the entity class and the handle class can be obtained directly through the function, and the friend is also declared, which makes the data class and the handle class even access rights.

And for the convenience of the call in the CPP file, the following two macros are declared directly

#define Q_D (Class) class# #Private * Const D = D_func ()
#define Q_Q (Class) class * Const Q = Q_func ()

Well, it's easy to use, but later local variables can never be declared as D and Q.

Here the D_func and Q_func functions are very common functions that can be understood as one is to get the data class, and the other is to get the Qt interface class

Qobject *parent;
This points to the parent class of Qobject
Qobjectlist children;
This points to the list of Qobject related subclasses
This is really a bold design, if the system produces 1 million Qobject instances (for large systems, this number is easy to achieve it), each Qobject sub-class average is 100 (this number may be large),
The overhead of these pointers is 1000000*100*4=400m, scary enough, and if we have to make a choice between flexibility and operational overhead, QT chooses the former, and it's hard for me to comment on the pros and cons,
Or to pray for more and more hardware levels and QT so many years to get the illustrious fame bless us there is no such a problem, hehe
In short, QT does save the tree structure of all class instances in memory

UINT Iswidget:1;
UINT Pendtimer:1;
UINT Blocksig:1;
UINT Wasdeleted:1;
UINT Ownobjectname:1;
UINT Sendchildevents:1;
UINT Receivechildevents:1;
UINT Unused:25;
The code is simple, mainly some marker bits, in order to save memory overhead, the syntax of bit field is used here, and 25 bits of unused are reserved.

#ifdef Qt3_support
int postedchildinsertedevents;
#else
int reserved;
#endif

This may be to be compatible with QT3 serialized data, even if no qt3_support is defined, still retains a data reserved to ensure the size of the entire qobjectdata unchanged

Let's take a look at an example, deepen the understanding of this handle entity pattern, which is the button class in Qt Qpushbutton
The handle class derivation for Qpushbutton is:
Qobject
Qwidget
Qabstractbutton
Qpushbutton

The entity class derivation relationships of Qpushbutton are:
Qobjectdata
Qobjectprivate
Qwidgetprivate
Qabstractbuttonprivate
Qpushbuttonprivate

As can be seen, this is really a parallel system, but the entity class derivation relationship more than one qobjectprivate, this class encapsulates the threading, signal and groove mechanism and other specific implementation, it can be said that it is the QT entity class
The base class that really works, and Qobjectdata is just a shallow layer of data encapsulation.

First of all, to understand the interfaces and implementations in the Qobjectprivate class, let's look at how the two systems of handle classes and entity classes are structured in QT.

qpushbutton* quit = new Qpushbutton ("Quit");

Create a Qt button, a simple line of code, in fact, there is a lot of mystery behind

Qpushbutton::qpushbutton (const QString &text, Qwidget *parent): Qabstractbutton (*new qpushbuttonprivate, parent)

First, the constructor of the Qabstractbutton is called in the Qpushbutton constructor, and a Qpushbuttonprivate entity class is immediately new, and then the pointer is converted to a reference to the Qabstractbutton

Qabstractbutton::qabstractbutton (qabstractbuttonprivate &dd, Qwidget *parent): QWidget (DD, parent, 0)

The constructor of the base class Qwidget continues to be called in the Qabstractbutton constructor, while the Qpushbuttonprivate entity class pointer continues to be passed to the base class

Qwidget::qwidget (Qwidgetprivate &dd, qwidget* parent, Qt::wflags F): Qobject (DD, ((Parent && (parent-> Windowtype () = = Qt::D esktop))? 0:parent)), Qpaintdevice ()

Qwidget continued to sit on the same thing

Qobject::qobject (qobjectprivate &dd, Qobject *parent): D_ptr (&DD)

Finally to the base class Qobject, here directly to the Qpushbuttonprivate pointer assigned to the D_PTR (remember the variable name it)

The new qpushbuttonprivate generated at the end of the Qpushbutton construct is written to D_ptr in Qobject.

Qobject::qobject (qobjectprivate &dd, Qobject *parent)
: D_ptr (&DD)
{
Q_d (Qobject);
:: Qt_addobject (d_ptr->q_ptr = this);
Qthread *currentthread = Qthread::currentthread ();
D->thread = CurrentThread? Qthreaddata::get (CurrentThread)->id:-1;
Q_assert_x (!parent | | parent->d_func ()->thread = = D->thread, "Qobject::qobject ()",
"Cannot create children for a parent," in a different thread. ");
if (parent && parent->d_func ()->thread! = d->thread)
parent = 0;
if (d->iswidget) {
if (parent) {
D->parent = parent;
D->parent->d_func ()->children.append (this);
}
No events sent here, this is do at the end of the Qwidget constructor
} else {
SetParent (parent);
}
}

And then execute the Qobject constructor, where the main is the processing of some threads, ignoring it first

Qwidget::qwidget (Qwidgetprivate &dd, qwidget* parent, Qt::wflags F)
: Qobject (DD, ((parent && () = = Qt::D esktop)), 0:parent), Qpaintdevice ()
{
D_func ()->init ((Parent && parent->windowtype () = = Qt::D esktop? parent:0), f);
}

Then there is the Qwidget constructor, which calls the INIT function of the data class Qwidgetprivate, which is not a virtual function, so the INIT function calls that are statically parsed into qwidgetprivate

Qabstractbutton::qabstractbutton (qabstractbuttonprivate &dd, Qwidget *parent)
: Qwidget (DD, parent, 0)
{
Q_d (Qabstractbutton);
D->init ();
}

Then there is the Qabstractbutton constructor, which calls the INIT function of the data class Qabstractbutton, which is not a virtual function, so the INIT function calls that are statically parsed into Qabstractbutton

Qpushbutton::qpushbutton (const QString &text, Qwidget *parent)
: Qabstractbutton (*new qpushbuttonprivate, parent)
{
Q_d (Qpushbutton);
D->init ();
SetText (text);
}

Then there is the Qpushbutton constructor, which calls the INIT function of the data class Qpushbutton, which is not a virtual function, so the INIT function calls that are statically parsed into Qpushbutton

Now the thing is very clear, summed up:
Qpushbutton constructs a qpushbuttonprivate pointer at the same time, qpushbuttonprivate the constructor of the data class base class when it is created
The constructor for the base class is called in the constructor of Qpushbutton, and the Qpushbuttonprivate pointer passes past, and the constructor of the interface class base class is called Qpushbutton when it is created
The init function of the parallel data class is called in the constructor of the interface class, because this function is not a virtual function, so this is the INIT function that called the data class.

It is necessary to point out why the Qpushbuttonprivate entity class pointer is being converted to a reference. Why not pass the pointer directly? conclusion is that people like to write, that is, do not pass the pointer to the reference, and to use a *new and other strange grammar,
There is no way, in fact, the pointer is the same here, the code looks natural.

Delete quit;
Finish the construction, say the destruction

Qpushbutton::~qpushbutton ()
{
}

Of course this will call the Qpushbutton destructor.

Qabstractbutton::~qabstractbutton ()
{
#ifndef Qt_no_buttongroup
Q_d (Qabstractbutton);
if (D->group)
D->group->removebutton (this);
#endif
}

And then the Qabstractbutton destructor.

Qwidget::~qwidget ()
{
Q_d (Qwidget);
...
}

Then there is the Qwidget destructor, which voluminous a lot of code, regardless of its

Qobject::~qobject ()
{
...
}

And finally, Qobject's destructor, and here's a whole bunch of voluminous.

    Q_d (Qobject);
if (d->wasdeleted) {
#if defined (qt_debug)
Qwarning ("Double qobject deletion detected");
#endif
Return
}
D->wasdeleted = true;

There is nothing to say, is to set a wasdeleted flag, to prevent re-quoted, for single-threaded case, will be removed immediately, and what Mark Ah, it is useless, but for multi-threaded case, this tag should be useful

   Set all qpointers for this object to zero
Guardhash *hash =:: Guardhash ();
if (hash) {
Qwritelocker Locker (Guardhashlock ());
Guardhash::iterator it = Hash->find (this);
Const Guardhash::iterator end = Hash->end ();
while (it.key () = = This && it! = end) {
*it.value () = 0;
it = hash->erase (it);
}
}

Here is the implementation code that supports qpointers, we'll talk about it later.

Emit destroyed (this);

When a pointer to Qt is deleted, a destroyed signal is sent, and normally there is no slot to respond.

Qconnectionlist *list =:: Connectionlist ();
if (list) {
Qwritelocker Locker (&list->lock);
List->remove (this);
}

This clears the record in the signal slot mechanism.

   if (D->pendtimer) {
Have pending timers
Qthread *thr = thread ();
if (thr | | d->thread = = 0) {
Don ' t unregister timers in the wrong thread
Qabstracteventdispatcher *eventdispatcher = qabstracteventdispatcher::instance (THR);
if (Eventdispatcher)
Eventdispatcher->unregistertimers (this);
}
}

Here, clear the timer.

D->eventfilters.clear ();

This clears the event filtering mechanism

    Delete Children objects
if (!d->children.isempty ()) {
Qdeleteall (D->children);
D->children.clear ();
}

This clears all the child class pointers, and of course each child class pointer clears up all its subclasses, so the new pointer in Qt seldom shows the corresponding delete because the topmost pointer is removed by the frame,
All the subclasses associated with it are automatically deleted.

{
Qwritelocker Locker (Qobjectprivate::readwritelock ());
:: Qt_removeobject (this);

/*
Theoretically, we cannot check d->postedevents without
Holding the Posteventlist.mutex for the object ' s thread,
But since we hold the Qobjectprivate::readwritelock (),
Nothing can go into qcoreapplication::p ostevent (), which
Effectively means noone can post new events, which is
We are trying to prevent. This means we can safely check
D->postedevents, since we are fairly sure it won't
Change (it could, but decreasing, i.e removing
Posted events from a DIFFEREBNT thread)
*/
if (d->postedevents > 0)
Qcoreapplication::removepostedevents (this);
}

if (d->parent)/remove it from parent object
D->setparent_helper (0);

Delete D;
d_ptr = 0;

QT Source Analysis Qobject (from CSDN, author Oowgsoo)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.