Preface, why first say this.
We know that in C + +, there is a need for some class member variables (class member variable) in almost every class, as in normal practice:
Class Person
{
Private
String Mszname; Name
BOOL Mbsex; Gender
int mnage; Age
};
Is that the class member variables are defined here directly in the class definition, and even if the access scope of these member variables is directly defined as public, are you doing this?
In Qt, it's almost not the case, so what does QT do?
Almost every C + + class will save a lot of data, to read someone else's written C + + code, it is necessary to know how each class of data is stored, what meaning, otherwise, we can not read someone else's C + + code. In this case, in order to read QT code, the first step is to understand how Qt's class member data is stored.
To make it easier to understand how Qt defines class member variables, let's start with the class member variable definition method in the QT 2.x version, because the method in 2.x is very easy to understand. Then describe the class member variable definition method in QT 4.4.
Methods in QT 2.x
When defining class (in the. h file), there is only one class member variable, only one member data pointer is defined, and then this pointer points to a data member object that contains all of the class's member data, and then in the class implementation file (. cpp file) , define this private data member object. The sample code is as follows:
//------------------------------------------------------------------------------------------------------------- -
File Name:person.h
struct personaldataprivate; Declaring private data member types
Class Person
{
Public
Person (); Constructor
Virtual ~person (); destructor
void setage (const int);
int Getage ();
Private
Personaldataprivate* D;
};
//------------------------------------------------------------------------------------------------------------- -
File Name:person.cpp
struct Personaldataprivate//defining private data member types
{
String Mszname; Name
BOOL Mbsex; Gender
int mnage; Age
};
Constructor
Person::P Erson ()
{
d = new Personaldataprivate;
};
destructor
Person::~person ()
{
Delete D;
};
void Person::setage (const int age)
{
if (age! = d->mnage)
D->mnage = age;
}
int Person::getage ()
{
Return d->mnage;
}
When I first learned QT, I thought it was a lot of trouble, but as the use increased, I started to like it, and now I'm writing code that basically uses this method. Specifically, it has the following advantages:
* Reduce the dependency of the header file
Put the specific data members into the CPP file, so that when you need to modify the data members, only need to change the CPP file without the need for a header file, so you can avoid the first time because of the changes in the header file, all the files containing this file are all recompiled once, Especially when this header file is very low on the header file and the project is very large, the advantages are obvious.
It also reduces the dependency of the header file on other header files. You can include only one time in the CPP file that is needed in the data member, and you can reduce the include statement as much as possible in the header file
* Enhanced encapsulation of classes
This method enhances the encapsulation of the class, and can no longer directly access the class member variables, but must write the corresponding Get/set member function to do these things.
Everyone has a different point of view on this issue, benevolent see and the other. Some people just like to define a class member variable as public, which is convenient when used. But I personally do not like this method, when the project becomes very large, there are a lot of people in the project together when the code is written in the bottom of a lot of people need to use (#include), the shortcomings of this method is fully reflected.
And, I don't like QT 2.x. The variable names of data members are defined as only one letter, D, which seems to be not intuitive, especially when search is inconvenient. But that's exactly what the QT kernel did.
So, how is it implemented in the latest QT4? Please follow the next section.
Methods in QT 4.4.x
In QT 4.4, the starting point of the class member variable definition method has not changed, but there has been a very big change in the concrete means of implementation, the following specific view.
In Qt 4.4, using a lot of macros to do things, this has increased the difficulty of understanding QT source code, do not know whether they are from the MFC learning. Even in the case of defining class member data variables, a large number of macros are used.
In this version, the class member variable no longer defines a private member for each class, but instead puts the work of this common in the most basic base class Qobject, and then defines some related methods to access it, OK, let's go into the specific code.
//------------------------------------------------------------------------------------------------------------- -
File Name:qobject.h
Class Qobjectdata
{
Public
Virtual ~qobjectdata () = 0;
Omitted
};
Class Qobject
{
Q_declare_private (Qobject)
Public
Qobject (Qobject *parent=0);
Protected
Qobject (qobjectprivate &dd, Qobject *parent = 0);
Qobjectdata *d_ptr;
}
This code is in the Qobject.h header file. In the definition of Qobject class, we see that the data clerk is defined as: Qobjectdata *d_ptr; The definition of protected type is to allow all derived classes to access the variable, while externally it cannot access the variable directly. The definition of qobjectdata is placed in this header file, the purpose is to want all the classes inherited from the Qobject member variables are also corresponding to the Qobjectdata this class inherit. The pure virtual destructor also determines two things:
* This class cannot be instantiated directly. In other words, if you write such a line of code, new Qobjectdata, this line of code will be wrong, compile can not pass the time.
* When you delete this pointer variable, this pointer variable is a point to any object inherited from Qobjectdata, this object can be deleted correctly without generating errors, such as memory leaks.
Let's take a look at what this macro did, Q_declare_private (Qobject)
#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;
This macro is mainly defined by the two overloaded functions, D_func (), the role is to qobject the class defined in the data member variable d_ptr safe conversion into each specific class data member type pointer. Let's see what happens after this macro unfolds in the class of Qobject.
Q_declare_private (Qobject) expands, it is the following code:
Inline qobjectprivate* D_func () {return reinterpret_cast<qobjectprivate *> (d_ptr);}
Inline const qobjectprivate* D_func () const
{return reinterpret_cast<const qobjectprivate *> (d_ptr);} /
Friend class Qobjectprivate;
After the macro unfolds, the new question comes again, where does the qobjectprivate come from. In Qobject this class, why not use Qobjectdata directly to the type of the data member variable.
Remember what we said just now, qobjectdata the pure virtual function of this class destructor, which means that this class is not instantiated, so qobject the actual type of the class member variable, which is inherited from Qobjectdata, It's qobjectprivate!
This class holds a number of very important and interesting things, including QT's core signal and slot data, attribute data, and so on, which we'll explain in detail later, and now let's look at its definition:
Here is the definition of this class:
Class Qobjectprivate:public Qobjectdata
{
Q_declare_public (Qobject)
Public
qobjectprivate (int version = qobjectprivateversion);
Virtual ~qobjectprivate ();
Omitted
}
So, what is the relationship between this qobjectprivate and Qobject? How they relate to each other.
====================================
Statement:
The Inside QT Series column is the original technical article of the QT Core Technology Forum (insideqt.com).
This series of columns may be reproduced at will, but this paragraph and the original address of each article must be retained.
The author retains the copyright and may not use it for any commercial purpose without the consent of the author
Inside Qt Series (iv): Object data Storage (C)
Author: q-kevin @ http://www.qkevin.com
Next, let's take a look at how this qobjectprivate and Qobject are linked together.
————————————————————————————————————–
File Name:qobject.cpp
Qobject::qobject (Qobject *parent)
: D_ptr (New Qobjectprivate)
{
...........................
}
Qobject::qobject (qobjectprivate &dd, Qobject *parent)
: D_ptr (&DD)
{
.....................
}
How, is not at a glance AH.
From the first constructor it is clear that the d_ptr pointer in the Qobject class will point to a Qobjectprivate object, and Qobjectprivate this class is inherited from Qobjectdata.
What is this second constructor for? From the definition of Qobject class, we can see that this second constructor is defined as the protected type, which means that the constructor can only be used by the inherited class, and cannot use this constructor to construct a Qobject object directly, that is to say, If you write one of the following statements, the compilation will fail,
New Qobject (*new qobjectprivate, NULL)
To see more clearly, we use the class of qwidget as an example to illustrate.
Qwidget is the base class for all UI controls in Qt, and it inherits directly from Qobject.
Class Qwidget:public Qobject, public qpaintdevice
{
Q_object
Q_declare_private (Qwidget)
.....................
}
Let's look at a code for this class's constructor:
Qwidget::qwidget (Qwidget *parent, Qt::windowflags f)
: Qobject (*new qwidgetprivate, 0), Qpaintdevice ()
{
D_func ()->init (parent, f);
}
It is very clear that it invokes the constructor for the protection type of the base class Qobject and is passed in as the first parameter with *new qwidgetprivate. In other words, the d_ptr pointer in the base class (Qobject) will point to an object of type Qwidgetprivate.
And look at the definition of the class Qwidgetprivate:
Class Qwidgetprivate:public Qobjectprivate
{
Q_declare_public (Qwidget)
.....................
}
Well, it's all connected.
About the only statement in the Qwidget constructor D_func ()->init (parent, F) We note that there is a sentence in the definition of class: Q_declare_private (Qwidget)
We've talked about this macro before, and when this macro is expanded, it's like this:
Inline qwidgetprivate* D_func () {return reinterpret_cast<qwidgetprivate *> (d_ptr);}
Inline const qwidgetprivate* D_func () const
{return reinterpret_cast<const qwidgetprivate *> (d_ptr);} \
Friend class Qwidgetprivate;
It is clear that it is converting the d_ptr pointer defined in Qobject to a pointer of type qwidgetprivate.
Summary:
To understand the code of QT kernel, it is necessary to know how the data inside each of the objects within Qt is stored, and QT does not have all the variables defined directly in the class as we normally write code, so we cannot understand a corresponding class without knowing the problem. In fact, the method of preserving class member data in Qt4.6 is essentially the same as in qt2.x, which is to define a pointer to a member's data in class, pointing to the member data collection object (here is a qobjectdata or its derived class). The way to initialize this member variable is to define a constructor for the type of protection, and then in the constructor of the derived class new a data member of the derived class and assign the new object to the Qobject data pointer. When used, the data pointer is converted to a security type by pre-defining an inline function in the macro, which can be used.
======================================================================
Statement:
The Inside Qt Series column is an original technical article (http://www.qkevin.com).
This series of columns may be reproduced at will, but this paragraph and the original address of each article must be retained.
The author retains the copyright and may not use it for any commercial purpose without the consent of the author