Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Qt use d_func() for instantiating a pointer to private data?

Tags:

c++

pointers

qt

Consider the following Qt class:

#include <QScopedPointer>

class MyClassPrivate;
class MyClass
{
    public:
        MyClass();
        ~MyClass();
    private:
        QScopedPointer<MyClassPrivate> d_ptr;
        Q_DECLARE_PRIVATE(MyClass)
}

This class resembles the structure of most Qt classes that implement private implementation. The macro Q_DECLARE_PRIVATE will cause the following expansion (as of Qt5):

inline MyClassPrivate* d_func()
    { return reinterpret_cast<MyClassPrivate *>(qGetPtrHelper(d_ptr)); }
inline const MyClassPrivate* d_func() const
    { return reinterpret_cast<const MyClassPrivate *>(qGetPtrHelper(d_ptr)); }
friend class MyClassPrivate;

This is confusing - why isn't d_ptr used directly in member functions? In other words, instead of doing this:

Q_D(MyClass);
d->member = 12345;

Why not do this?

d_ptr->member = 12345;

What is the reason for having an explicit function that (basically) just returns the d_ptr and incurs the overhead of an extra variable on the stack?

like image 629
Nathan Osman Avatar asked Apr 10 '13 00:04

Nathan Osman


1 Answers

If the derived class and base class each has a Private structure, it would waste more memory, thus in Qt, the private class is also inherited, and the derived class and the base class shares one d_ptr. The problem of doing so is that the d_ptr is now of type BasePrivate.

class Base
{
protected:
    BasePrivate * d_ptr;
}

class Derived
{
// There is not d_ptr declared
}

So you can see, in the derived class, when it access d_ptr, the type is BasePrivate*. So it needs to cast d_ptr to DerivedPrivate*. The d_func function is inline, once compiled, it will always cast the d_ptr to the correct type.

This post illustrates better than what I say here, I suggest you read it.

like image 170
Min Lin Avatar answered Nov 05 '22 23:11

Min Lin