D指针/ pimpl模式基类指针访问派生类成员

时间:2017-05-26 01:42:13

标签: c++ qt

我对此链接中的概念存在误解。 http://wiki.qt.io/D-Pointer

在继承d-pointers进行优化的部分中, 在创建Label对象时,请说

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

的值为

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;
};

我知道对象B可以访问受保护的成员d_ptr,它是一种WidgetPrivate *。我的问题是,可以使用此d_ptr访问LabelPrivate中的文本成员吗?

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

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

为避免含糊不清,我在这里发布原始资料: widget.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_p.h

Widget::Widget() : d_ptr(new WidgetPrivate(this))
{
}

Widget::Widget(WidgetPrivate &d) : d_ptr(&d)
{
}

widget.cpp

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.h

#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)
{
}

label.cpp

{{1}}

1 个答案:

答案 0 :(得分:0)

对于Widget,d_ptr只是一个WidgetPrivate *。 Label必须将其强制转换回LabelPrivate *才能访问其内容。

如果您在您引用的页面上进一步阅读了一节,您将看到实际获取LabelPrivate内容的完整代码:

void Label::setText(const String &text)
{
    LabelPrivate *d = static_cast<LabelPrivate*>(d_ptr); // cast to our private type
    d->text = text;
}

然后该文档继续描述一些隐藏这种冗长的Qt宏,但实现仍然是相同的。

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

一旦您进入Label实现,您就可以将PIMPL指针重新转换回您知道的子类版本(LabelPrivate),并拥有对内容的完全访问权。