Qt d指针q指针

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wyy626562203/article/details/82419236

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

猜你喜欢

转载自blog.csdn.net/wyy626562203/article/details/82419236