PDA

View Full Version : Virtual class as a QWidget interface and dependency inversion principle.



porterneon
17th November 2011, 13:48
Hi
I have classes named IStorage and Storage. For example:


class IStorage : public QWidget {
Q_OBJECT
public:
virtual void Method1(const QString &par1);

signals:
void IStorageSignal1(const QString &par1);

public slots:
virtual void SetVariableValue(const int &val);
};

and


namespace Ui {
class Storage ;
}
class Storage : public IStorage {
Q_OBJECT
public:
explicit Storage();
public slots:
void SetVariableValue(const int &val);
private:
int localVariable;
};


How to (fallowing dependency inversion principle) implement class "MainWidgetDisplay" to make it independent from IStorage and to be able to connect with IStorage's signals and slots?

d_stranz
17th November 2011, 22:53
There is no problem in using virtual slots, so if you write code like this:



void MainWidgetDisplay::makeConnectionsToIStorage( IStorage * someStorage )
{
connect( someStorage, SIGNAL( IStorageSignal1( const QString & ) ), this, SLOT( myHandler( const QString & ) ) );
connect( this, SIGNAL( setVariableValue( const int & ) ), someStorage, SLOT( SetVariableValue( const int & ) ) );
}


Then if at runtime "someStorage" actually is a "Storage *" pointer, then everything should work as you expect.

The Storage class can emit the IStorageSignal1 signal, and when MainWidgetDisplay emits it's setVariableValue() signal, the correct Storage slot will be called. MainWidgetDisplay.cpp needs to include IStorage.h and that's all. It doesn't need to know about classes derived from IStorage if it only uses the virtual methods.

Santosh Reddy
18th November 2011, 04:17
How to (fallowing dependency inversion principle) implement class "MainWidgetDisplay" to make it independent from IStorage and to be able to connect with IStorage's signals and slots?
If you want to implement MainWidgetDisplay independent of IStorage you could well do it. One simple trick is to check your dependency is make sure that you don't include IStorage.h file from MainWidgetDisplay implementation and header files either directly or indirectly. So if you want to connect signal and slots between them, the signal and slots connections SHOULD NOT be made from either off these two classes. The signal and slots connections between them should be made by some other class generally by the parent object class implementation (as in below example)

//Example SomeClass (parent objects's class)
#include "SomeClass.h"
#include "IStorage.h"
#include "MainDisplayWidget.h"


void SomeClass::ShowMainWidget(void)
{
IStorage* storage = new IStorage(this);
MainDisplayWidget* widget = new MainDisplayWidget(this);

// IStorage Signal >>>>>>>>>>>>>>>> MainDisplayWidget Slot
connect(storage, SIGNAL(IStorageSignal(const QString)), widget, SLOT(MainDisplayWidgetSlot(const QString)));

// MainDisplayWidget Signal >>>>>>>>>>>>>>>> IStorage Slot
connect(widget, SIGNAL(MainDisplayWidgetSignal(const QString)), storage, SLOT(IStorageSlot(const QString)));
}

This way MainDisplayWidget is independent of IStorage, and also IStorage is independent of MainDisplayWidget.

d_stranz
18th November 2011, 17:55
I think I misread the original post to say "independent of Storage" (not IStorage). As usual, Santosh has a good approach, which I actually use all the time when I want to connect two objects that don't need to know anything about each other.

amleto
18th November 2011, 20:32
you can just forward declare the classes and you can still connect signals slots I think.

Also, I'm not sure about your idea of dependency inversion - The method is to make the higher level class dependant on the abstraction - IStorage. So there is no problem with mainwindow being dependant up on it, because it is an abstraction.

Santosh Reddy
18th November 2011, 23:12
you can just forward declare the classes and you can still connect signals slots I think.


Also, I'm not sure about your idea of dependency inversion - The method is to make the higher level class dependant on the abstraction - IStorage. So there is no problem with mainwindow being dependant up on it, because it is an abstraction.

I think the OP wanted MainDisplayWidget to be independent of the abstraction class itself (or the interface class itself), which is IStorage class in this case.

Forward class declaration will make MainDisplayWidget class declaration independent of the IStorage class implementation / declaration (or Interface implementation / declaration) but MainDisplayWidget class implementation still has to dependent on IStorage class declaration.