Application and implementation of D-pointer on QT (d-pointer for binary compatibility)

Source: Internet
Author: User

QT introduces the concept of D-pointers in order to maximize binary compatibility for its dynamic libraries. So why is the D pointer binary compatible? To answer this question, first figure out what binary compatibility is? The so-called binary compatible dynamic library, refers to a program that runs under the old repository, can still run under the new repository without compiling it, and it needs to be compiled to run under the new version without modifying the program source code, we say that the dynamic library is source code compatible. To enable a DLL to achieve binary compatibility, for a structure, for an object, its data model should be unchanged, if there are changes, such as the addition of data members in the class or delete data members, the result will certainly affect the object's data model, resulting in the original data path in the object data model displacement changes, In this case, the compiled new repository is likely to cause the program to crash, in order to make the object data model size change after adding and adding items, one way is to pre-allocate several reserved spaces, and use the hold when adding items. As follows:

[HTML]View PlainCopy
    1. Class A {
    2. Private
    3. int A;
    4. int reserved[3];
    5. };
    6. Class B {
    7. Private
    8. int A;
    9. Quint32 b:1;
    10. Quint32 reserved:31;
    11. };

In this case, when adding items, you only need to use the reserved space, so the object model will not change. But this is very inflexible, because you do not know how many extensions will be in the future, the lack of unmet requirements, more wasted space. So is there a more flexible approach? As follows:

[HTML]View PlainCopy
    1. Class Data {
    2. Public
    3. int A;
    4. };
    5. Class A {
    6. Private
    7. Data *d_ptr;
    8. };

Put the member A in the data, a a pointer to the data, so that no matter how much data you add to the database, A's object model is always the size of 4 bytes (d_ptr pointer size), this is not more flexible than the above approach? D_ptr is what we're going to say today. D Pointer, QT in order to achieve binary compatibility, the majority of the class contains such pointers, let's look at how QT D pointer is implemented:



For example, this is the general form of the pointer to the QT root node, and below is a look at the general form of the non-root node,

Note here that Qwidge derives from Qobject, which does not have d_ptr, but its member functions can access d_ptr because D_ptr is a protected member, and its object model contains D_PTR (this is because derived classes inherit all members of the parent class).

Let's look at how QT is implemented for both of these scenarios:

Qobject.h file:

[HTML]View PlainCopy
  1. Qobjectdata {
  2. Public
  3. Qobject *q_ptr;
  4. ...
  5. };
  6. Class Q_core_export Qobject
  7. {
  8. ...
  9. Q_declare_private (Qobject)
  10. Public
  11. Q_invokable Explicit Qobject (Qobject *parent=0);
  12. Virtual ~qobject ();
  13. ...
  14. Protected
  15. Qobject (qobjectprivate &dd, qobject *parent = 0);
  16. ...
  17. Protected
  18. Qscopedpointer<qobjectdata> d_ptr;
  19. ...
  20. };

As above, here I counted the other items, only kept the d_ptr related items, first of all to see what Q_declare_private (Qobject) is:

[HTML]View PlainCopy
    1. #define Q_DECLARE_PRIVATE (Class) \
    2. Inline class# #Private * D_func () {return reinterpret_cast<class# #Private *> (qgetptrhelper (D_ptr));} \  
    3. inline Const class# #Private * D_FUNC () const {return reinterpret_cast<const class# #Private *> ( Qgetptrhelper (d_ptr)); } \  
    4. Friend class class# #Private;

According to the macro definition, q_declare_private (qobject) translates as follows:

[HTML]View PlainCopy
    1. Inline Qobjectprivate *d_func ()
    2. {
    3. return reinterpret_cast<qobjectprivate *> (qgetptrhelper (d_ptr));
    4. }
    5. Inline const qobjectprivate *d_func () const
    6. {
    7. return reinterpret_cast<const qobjectprivate *> (qgetptrhelper (d_ptr));
    8. }
    9. Friend class Qobjectprivate;


Then look at the definition of Qgetptrhelper:

[HTML]View PlainCopy
    1. Template <typename T> static inline t *qgetptrhelper (t *ptr)
    2. {
    3. return ptr;
    4. }

Then look at Qscopepointer, it is similar to the smart pointer, so do not care about the release of D_ptr, when leaving the scope of Qscopepointer, Qscopepointer will automatically release D_ptr point to the heap memory, then when this pointer is generated? When was q_ptr assigned? Let's take a look at the implementation of Qobject.cpp:

[HTML]View PlainCopy
  1. Qobject::qobject (Qobject *parent)
  2. : D_ptr (New Qobjectprivate)
  3. {
  4. Q_d (Qobject);
  5. d_ptr->q_ptr = this ;
  6. ...
  7. }
  8. Qobject::qobject (qobjectprivate &dd, Qobject *parent)
  9. : D_ptr (&DD)
  10. {
  11. Q_d (Qobject);
  12. d_ptr->q_ptr = this ;
  13. ...
  14. }

We look at the first constructor, the d_ptr of the root node points to new qobjectprivate, and qobjectprivate derives from Qobjectdata, so what does the Q_d (QOBJECT) macro mean?

[HTML]View PlainCopy
    1. #define Q_D (Class) class# #Private * Const D = d_func ()

Q_d (Qobject), translated as follows:

[HTML]View PlainCopy
    1. Qobjectprivate * Const d = d_func ();

It is not difficult to see Q_d (Qobject); Defines a Qobjectprivate constant pointer to the return value of D_func (), which is d_ptr (see header file D_func () definition), so we can access the D pointer with the Q_D macro.

For the second constructor, let's take a look at the implementation of the non-root node d_ptr:

Header file:

[HTML]View PlainCopy
  1. Class Q_core_export Qobjectprivate:public Qobjectdata
  2. {
  3. Q_declare_public (Qobject)
  4. ...
  5. };
  6. Class Q_gui_export Qwidgetprivate:public Qobjectprivate
  7. {
  8. Q_declare_public (Qwidget)
  9. ...
  10. };
  11. Class Q_gui_export Qwidget:public Qobject
  12. {
  13. ...
  14. Q_declare_private (Qwidget)
  15. ...
  16. Public
  17. ...
  18. Explicit Qwidget (qwidget* parent = 0, qt::windowflags f = 0);
  19. ...
  20. };

Let's look at Q_declare_public macro first:

[HTML]View PlainCopy
    1. #define Q_DECLARE_PUBLIC (Class) \
    2. Inline class* Q_func () {return static_cast<Class *> (q_ptr);} \
    3. Inline const class* Q_func () const {return static_cast<const CLASS *> (q_ptr);} \
    4. Friend Class class;

According to the macro definition, q_declare_public (qobject) translates as follows:

[HTML]View PlainCopy
    1. Inline Qobject *q_func ()
    2. {
    3. return static_cast<qobject *> (q_ptr);
    4. }
    5. Inline const Qobject *q_func () const
    6. {
    7. return static_cast<const Qobject *> (q_ptr);
    8. }
    9. Friend class Qobject;

Q_declare_public (Qwidget) translates as follows:

[HTML]View PlainCopy
    1. Inline Qwidget *q_func ()
    2. {
    3. return static_cast<qwidget *> (q_ptr);
    4. }
    5. Inline const Qwidget *q_func () const
    6. {
    7. return static_cast<const Qwidget *> (q_ptr);
    8. }
    9. Friend class Qwidget;

Note that the q_ptr here are publicly declared in Qobjectdata, and qobjectprivate,qwidgetprivate are derived or indirectly derived from Qobjectdata, so you can access q_ptr.

Next look at the translation of Q_declare_private (Qwidget):

[HTML]View PlainCopy
    1. Inline Qwidgetprivate *d_func ()
    2. {
    3. return reinterpret_cast<qwidgetprivate *> (qgetptrhelper (d_ptr));
    4. }
    5. Inline const qwidgetprivate *d_func () const
    6. {
    7. return reinterpret_cast<const qwidgetprivate *> (qgetptrhelper (d_ptr));
    8. }
    9. Friend class Qwidgetprivate;

Next look at the implementation of the Qwidget constructor:

[HTML]View PlainCopy
    1. Qwidget::qwidget (Qwidget *parent, Qt::windowflags f)
    2. : Qobject (*new qwidgetprivate, 0)
    3. {
    4. ...
    5. }


See Qobject (*new qwidgetprivate, 0) here called the second constructor of Qobject, which points d_ptr to the heap memory pointed to by new qwidgetprivate.

http://blog.csdn.net/rabinsong/article/details/9474859

Application and implementation of D-pointer on QT (d-pointer for binary compatibility)

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.