How to use QNetworkAccessManager in different classes? General sharing of important data between classes?
Asked Answered
U

2

6

I have a MainWindow application I'm working on to learn C++ and Qt (C++ and QT 4.8). I want to do HTTP requests in different objects of my application, such as Dialogs/Wizard and in the MainWindow. I know I'm basically supposed to have one QNetworkAccessManager per application. My question is, what is the proper way to pass this QNAM around between classes?

At the moment I have it as a pointer I pass to the constructor of my wizard but this seems... inelegant and inflexible. What is the proper way to give my Dialogs or whatever other classes I decide to make, access to my one QNetworkAccessManager? I guess I have the same question about any piece of data I need to give everything access to.

What is the properly C++-designed solution here? The singleton pattern seems like an option, but a bad one as I understand. I have a bit of code here to show my question.

My MainWindow constructor and slot which launch my wizard:

MyMainWindow::MyMainWindow
{
    qnam = new QNetworkAccessManager();
}

...

MyMainWindow::wizardStarter
{
    mywizard = MyWizard(vari, qnam, this);
}

My Wizard Constructor in which I'm making network requests and parsing data after getting data from the user, and therefore in which I need a QNetworkAccessManager:

MyWizard::MyWizard(SomeOtherArgument *vari, QNetworkAccessManager *qnam, QObject *parent)
{
    ...
    this->ourQnam = qnam;
    ...
}

MyWizard::launchRequest(QUrl newUrl)
{
    ourQnam->get(QNetworkRequest(newUrl));
}
Unarm answered 3/7, 2012 at 15:1 Comment(4)
I recommend singleton design pattern. Why you think this pattern is bad?Interlocution
@hamed, singletons hide dependency relationships between classes if you do not use proper dependency injection. Nothing wrong with the singleton design pattern just use proper injection to communicate that your class depends upon your singleton.Dougald
How would one add proper injection in the case of a singleton?Unarm
@MJBoa, This example uses constructor injection you could do using another form: MyClass* myClass = new MyClass( MySingleton::getInstance() ); This still communicates 'MyClass' depends upon 'MySingleton' while allowing for use of singletons. It also allows you to easy swap out which singleton is used in the case of testing. See Why Singletons Are ControversialDougald
D
6

From your question, I think you're really asking which form of dependency injection (i.e. injecting your dependent QNetworkAccessManager into objects) to use.

In your case you're using Constructor injection. This is a perfectly known and accepted form of injection. It strongly communicates your wizard class depends upon the QNetworkAccessManager which makes your code easy for people to understand. If you were to use a singleton to simply grab a static QNetworkAccessManager from inside the wizard class implementation, while it has the benefit of removing the constructor injection, it hides that your wizard class uses the QNetworkAccessManager.

Another well known form of injection is Setter Injection i.e. setDelegate( delegate )

Professionally speaking there is nothing wrong with your current approach as again it clearly communicates your wizard class depends upon the QNetworkAccessManager object.

Here is a bit of reading if you if you're interested in learning more about dependency injection.

Dependency Injection

Dependency Injection in C++

Dougald answered 3/7, 2012 at 15:33 Comment(0)
C
0

Another way is shown in this post:

The canonical way to manage such global application-tied objects is to keep them as automatic variables in main and use helper functions to access them. The QPointer automatically tracks the lifetime of the object, and thus won't ever be dangling.

Thus:

main.h - interface

QNetworkAccessManager *nMgr();

main.cpp - implementation

// This pointer is local to the translation unit, and is an
// implementation detail. It's not used anywhere else.
static QPointer<QNetworkAccessManager> globalManager;

// The global accessor method
QNetworkAccessManager *nMgr() {
  Q_ASSERT(!qApp || QThread::currentThread() == qApp->thread());
  return globalManager;
}

int main(int argc, char *argv[]) {
  QApplication app(argc, argv);
  QNetworkAccessManager mgr;
  globalManager = &mgr;
  ...
}
Consequently answered 8/6, 2018 at 8:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.