三十二、Qt之 d 指针案例与解析

本案例目的:实现对 QNetworkAccessManager 的封装,获取 QNetworkAccessManager 单例,保证全局唯一

//NetWorker.h

#ifndef NETWORKER_H
#define NETWORKER_H

#include <QObject>
#include <QNetworkReply>

class NetWorker : public QObject
{
    Q_OBJECT
public:
    //获取单例
    static NetWorker * instance();
    ~NetWorker();

    void get(const QString &url);


signals:
    void finished(QNetworkReply *reply);

private:
    class Private;
    /**
     * Private 是 NetWorker 的友元类,在 Private 类中可以访问 NetWorker 的私有成员:比如本案例中访问
     * NetWorker 的私有构造函数
     */
    friend class Private;
    /**
     *     d 指针是 C++ 程序常用的一种设计模式。它的存在于 C++ 程序的编译有关。在 C++ 中,保持二进制兼
     * 容性非常重要。如果你能够保持二进制兼容,则当以后升级库代码时,用户不需要重新编译自己的程序即可直
     * 接运行(如果你使用 Qt5.0 编译了一个程序,这个程序不需要重新编译就可以运行在 Qt5.1 下,这就是二
     * 进制兼容;如果不需要修改源代码,但是必须重新编译才能运行,则是源代码兼容;如果必须修改源代码并且
     * 再经过编译,例如从 Qt4 升级到 Qt5,则称二者是不兼容的)。保持二进制兼容的很重要的一个原则是不要
     * 随意增加、删除成员变量。因为这会导致类成员的寻址偏移量错误,从而破坏二进制兼容。为了避免这个问题,
     * 我们将一个类的所有私有变量全部放进一个单独的辅助类中,而在需要使用这些数据的类值提供一个这个辅助
     * 类的指针。注意,由于我们的辅助类是私有的,用户不能使用它,所以针对这个辅助类的修改不会影响到外部
     * 类,从而保证了二进制兼容。
     */
    Private *d;

    /**
     * 单例模式,要求构造函数、拷贝构造函数和赋值运算符都是私有的
     */

    //构造函数
    explicit NetWorker(QObject *parent = nullptr);

    /**
     * 宏Q_DECL_EQ_DELETE代表=delete,这是C++11的语法,显式指示编译器不生成函数的默认版本。
     */
    //拷贝构造函数
    NetWorker(const NetWorker &) Q_DECL_EQ_DELETE;
    //赋值运算符
    NetWorker& operator=(NetWorker rhs) Q_DECL_EQ_DELETE;

public slots:
};

#endif // NETWORKER_H


--------------------------------------------------------
//NetWorker.cpp

#include "networker.h"

#include <QNetworkAccessManager>

/**
 *     NetWorker::Private类主要有一个成员变量QNetworkAccessManager *,
 * 把QNetworkAccessManager封装起来。NetWorker::Private需要其被辅助的类
 * NetWorker 的指针,目的是作为QNetworkAccessManager的 parent,以便 NetWorker
 * 析构时能够自动将QNetworkAccessManager析构。当然,我们也可以通过将NetWorker::Private
 * 声明为QObject的子类来达到这一目的。
 */
class NetWorker::Private
{
public:
    QNetworkAccessManager *manager;

    Private(NetWorker *q) : manager(new QNetworkAccessManager(q))
    {

    }
};

NetWorker::NetWorker(QObject *parent) :
    QObject(parent),
    d(new NetWorker::Private(this))
{
    //绑定信号与槽,当信号函数与槽函数参数类型、个数都一样时,可以写成这种格式
    //这里实现的时当 QNetworkAccessManager 发送 finished() 信号时, NetWorker 也发送 finished() 信号,实现信号的转发
    connect(d->manager, &QNetworkAccessManager::finished, this, &NetWorker::finished);
}

/**
 * 由于NetWorker::Private是在堆上创建的,并且没有继承QObject,所以我们必须手动调用delete运算符,
 * 删除 d 指针
 */
NetWorker::~NetWorker()
{
    delete d;
    d = 0;
}

/**
 * 这是 C++ 单例模式的最简单写法:
 * 由于 C++ 标准要求类的构造函数不能被打断,因此这样做也是线程安全的
 */
NetWorker *NetWorker::instance()
{
    static NetWorker netWorker;
    return &netWorker;
}
/**
* 实现对 http get() 方法的封装
*/
void NetWorker::get(const QString &url)
{
    d->manager->get(QNetworkRequest(QUrl(url)));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值