C++ D-pointer/pimpl模式基类指针访问派生类成员

C++ D-pointer/pimpl模式基类指针访问派生类成员,c++,qt,C++,Qt,我对这个环节的概念有误解 在继承用于优化的d指针一节中, 创建标签对象时,例如 Label B; 首先调用基构造函数,然后调用派生构造函数。由于派生构造函数采用这种形式: Label::Label() : Widget(*new LabelPrivate) // initialize the d-pointer with our own Private { } 这个基本构造函数被调用 Widget::Widget(WidgetPrivate &d) : d_ptr(&d)

我对这个环节的概念有误解


在继承用于优化的d指针一节中, 创建标签对象时,例如

Label B;
首先调用基构造函数,然后调用派生构造函数。由于派生构造函数采用这种形式:

Label::Label()
: Widget(*new LabelPrivate) // initialize the d-pointer with our own 
Private
{
}
这个基本构造函数被调用

Widget::Widget(WidgetPrivate &d) : d_ptr(&d)
{
}
基类成员

WidgetPrivate *d_ptr
将具有

*new LabelPrivate
我知道对象B可以访问WidgetPrivate*类型中的受保护成员d_ptr。我的问题是,是否可以使用此d_ptr访问LabelPrivate中的文本成员

如果是,我关心的是为什么WidgetPrivate*类型的d_ptr可以访问派生类成员文本

如果否,这是否意味着Label无法访问LabelPrivate中的成员文本,那么使用该模式有什么意义


为了避免歧义,我将原始材料张贴在此处: widget.h

小工具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)
{
}
标签.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)
{
}

对于小部件,d_ptr只是一个WidgetPrivate*。标签必须将其转换回LabelPrivate*才能访问其内容

如果您阅读所引用页面下方的一节,您将看到实际获取LabelPrivate内容的完整代码:

void Label::setText(const String &text)
{
    LabelPrivate *d = static_cast<LabelPrivate*>(d_ptr); // cast to our private type
    d->text = text;
}
void标签::setText(常量字符串和文本)
{
LabelPrivate*d=static_cast(d_ptr);//转换为我们的私有类型
d->text=文本;
}
然后,文档继续描述一些隐藏这种详细信息的Qt宏,但实现仍然是一样的

总结该模式的含义:顶级类和PIMPL指针都是层次结构。Widget(Label)的子类将PIMPL指针设置为WidgetPrivate(LabelPrivate)的子类。现在,小部件实现可以访问WidgetPrivate超类的任何部分,因为这是存储指针的协变类型(子类指针始终可强制转换到其超类)。但是,它对LabelPrivate子类一无所知


一旦进入标签实现,就可以将PIMPL指针重新转换回子类版本(LabelPrivate),并且可以完全访问其中的内容。

看起来d-pointer是PIMPL习惯用法实现的另一个名称。这里的
LabelPrivate
并不意味着它有私有成员,而是它是
Label
的“私有”细节。这就是我收集的…明白了。LabelPrivate是Label细节的一个实现。我的问题是,当LabelPrivate是WidgetPrivate的派生类时,为什么WidgetPrivate*ptr可以访问LabelPrivate的成员。这里没有给出
LabelPrivate
WidgetPrivate
的定义。我想
小部件
至少有两个构造函数。我们不需要参数,而是使用
new WidgetPrivate()
初始化
d\u ptr
。另一个接受一个
WidgetPrivate&
参数并初始化
d_ptr
,如图所示。对于小部件,d_ptr只是一个WidgetPrivate*。标签必须将其强制转换回LabelPrivate*才能访问其内容。因此,我可以说标签可以通过将WidgetPrivate*d_ptr强制转换为LabelPrivate*来访问LabelPrivate的文本成员吗?
void Label::setText(const String &text)
{
    LabelPrivate *d = static_cast<LabelPrivate*>(d_ptr); // cast to our private type
    d->text = text;
}