Reputation: 327
I have misunderstanding in the concept in this link. http://wiki.qt.io/D-Pointer
In the section Inheriting d-pointers for optimization, when creating a Label object, say
Label B;
The base constructor will be called first and then the derived constructor will be called. Since the derived constructor is in this form:
Label::Label()
: Widget(*new LabelPrivate) // initialize the d-pointer with our own
Private
{
}
This base constructor is called.
Widget::Widget(WidgetPrivate &d) : d_ptr(&d)
{
}
The base class member
WidgetPrivate *d_ptr
will have the value of
*new LabelPrivate
I know that the object B can access the protected member d_ptr which is in a type of WidgetPrivate *. My problem is, can one use this d_ptr to access the text member in LabelPrivate?
If yes, my concern is that why d_ptr in the type of WidgetPrivate* can have access to the derived class member text?
If no, does this mean Label has no access to the member text in LabelPrivate and then what is the point of using the pattern?
To avoid ambiguity, I post the original material here: widget.h
class Widget
{
public:
Widget();
// ...
protected:
// only subclasses may access the below
// allow subclasses to initialize with their own concrete Private
Widget(WidgetPrivate &d);
WidgetPrivate *d_ptr;
};
widget_p.h
struct WidgetPrivate
{
WidgetPrivate(Widget *q) : q_ptr(q) { } // constructor that initializes
the q-ptr
Widget *q_ptr; // q-ptr that points to the API class
Rect geometry;
String stylesheet;
};
widget.cpp
Widget::Widget() : d_ptr(new WidgetPrivate(this))
{
}
Widget::Widget(WidgetPrivate &d) : d_ptr(&d)
{
}
label.h
class Label : public Widget
{
public:
Label();
// ...
protected:
Label(LabelPrivate &d); // allow Label subclasses to pass on their Private
// notice how Label does not have a d_ptr! It just uses Widget's d_ptr.
};
label.cpp
#include "widget_p.h"
class LabelPrivate : public WidgetPrivate
{
public:
String text;
};
Label::Label()
: Widget(*new LabelPrivate) // initialize the d-pointer with our own Private
{
}
Label::Label(LabelPrivate &d) : Widget(d)
{
}
Upvotes: 0
Views: 601
Reputation: 14947
To a Widget, d_ptr is only a WidgetPrivate*. A Label would have to cast it back to a LabelPrivate* to access its contents.
If you read one section further down on the page you cite, you'll see the full code for actually getting to the contents of LabelPrivate:
void Label::setText(const String &text)
{
LabelPrivate *d = static_cast<LabelPrivate*>(d_ptr); // cast to our private type
d->text = text;
}
Then the document goes on to describe some Qt macros that hide this verbosity, but the implementation is still the same.
To summarize the implications of the pattern: Both the top-level class and the PIMPL pointer are hierarchies. A subclass of Widget (Label) sets the PIMPL pointer to a subclass of WidgetPrivate (LabelPrivate). Now a Widget implementation can access any part of the WidgetPrivate superclass, because that's the covariant type of the stored pointer (a subclass pointer is always castable to its superclasses). However, it knows nothing about the subclass LabelPrivate.
Once you're inside a Label implementation, you can recast the PIMPL pointer back to the subclass version (LabelPrivate) that you know is in there, and have full access to the contents.
Upvotes: 1