欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt d指针q指针

程序员文章站 2024-02-29 18:27:40
...

Qt d指针q指针

官方资料:http://wiki.qt.io/D-Pointer/zh

概述

如果程序从一个以前版本的库动态链接到新版本的库之后,能够继续正常运行,而不需要重新编译,那么我们就说这个库是二进制兼容的。如果一个程序需要重新编译来运行一个新版本的库,但是不需要对程序的源代码进一步的修改,这个库就是源代码兼容的。

Q_DECLARE_PRIVATE和Q_DECLARE_PUBLIC

template <typename T> static inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelper(const Wrapper &p) { return p.data(); }

Q_DECLARE_PRIVATE定义

#define Q_DECLARE_PRIVATE(Class) \
    inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \
    inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } \
    friend class Class##Private;

它实际上创建了两个 inline 的d_func()函数,返回值分别是我们的d_ptr指针和const指针,又把ClassPrivate声明为Class的友元,使得ClassPrivate可以访问Class中的私有成员。

Q_DECLARE_PUBLIC定义

#define Q_DECLARE_PUBLIC(Class)                                    \
    inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
    inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
    friend class Class;

与之前的宏相对,返回的是指向class的指针,因为我们可能在ClassPrivate的实现里访问Class的一些东西。让主类通过d_func()访问ClassPrivate的数据,反过来让ClassPrivate访问主类的数据用的就是q_func()

Q_Q和Q_D

以下两个宏对指针访问进行了简化,以后代码中使用d和q就可以了。

#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()

不能把ClassPrivate的头文件和Class头文件放到一起,常见做法是:定义一个ClassPrivate的头文件,例如使用myclass_p.h(这也是Qt的命名方式)。并且记住,不要把myclass_p.h放到发布的include下面!在myclass.h中,使用前向声明Class MyClassPrivate

d指针的优点

  • 隐藏实现细节
  • 头文件中没有任何实现细节,可以作为API使用。
  • 由于原本在头文件的实现部分转移到了源文件,所以编译速度有所提高。
  • 实现二进制兼容性,避免重新编译

应用实例

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
class WidgetPrivate;

class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = 0);
    ~Widget();

    QString getText() const;
    void setText(const QString &value);

    void test();

protected:
    //使用智能指针无需在析构函数中释放
    QScopedPointer<WidgetPrivate> d_ptr;
private:
    QString text;

    Q_DECLARE_PRIVATE(Widget)
    Q_DISABLE_COPY(Widget)
};

#endif // WIDGET_H

widgetprivate_p.h

#ifndef WIDGETPRIVATE_H
#define WIDGETPRIVATE_H

#include <QDebug>
#include <QScopedPointer>
class Widget;
class WidgetPrivate
{
    Q_DISABLE_COPY(WidgetPrivate)
    Q_DECLARE_PUBLIC(Widget)
public:
    WidgetPrivate(Widget *q);
    ~WidgetPrivate();
    Widget *const q_ptr;
    void init();
    void setWidgetText(QString text);
};

#endif // WIDGETPRIVATE_H

widget.cpp

#include "widget.h"
#include "widgetprivate_p.h"


WidgetPrivate::WidgetPrivate(Widget *q):q_ptr(q)
{

}
WidgetPrivate::~WidgetPrivate()
{

}

void WidgetPrivate::init()
{
    qDebug() << "get WidgetPrivate!";
}

void WidgetPrivate::setWidgetText(QString text)
{
    Q_Q(Widget);
    q->setText(text);
}


Widget::Widget(QWidget *parent)
    : QWidget(parent),d_ptr(new WidgetPrivate(this))
{
    //该方法获取d指针,Q_D是对它的封装
    d_func()->init();
}

Widget::~Widget()
{

}

void Widget::test()
{
    Q_D(Widget);
    //为了展示q指针的使用,在私有数据中调用主类的setText方法
    d->setWidgetText("set by WidgetPrivate!");
    qDebug() << getText();
}

QString Widget::getText() const
{
    return text;
}

void Widget::setText(const QString &value)
{
    text = value;
}

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.test();
    w.show();

    return a.exec();
}

相关标签: qt d-pointer