本案例目的:实现对 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)));
}