1

In my Qt5 program I have an interface with some signals.

An implementation of this interface is instanciated at start up and the signals are connected to from different parts of the program (many places).

Now I want to delete that instance and create a new instance, possibly from another implementation, and somehow maintain the signal connections so that all the places that receive the signals does not need to care that the implementation changed.

Is there any way to do this elegantly or do I have to change the architecture of program to keep control over all signal connections in one location (a lot of work)?

Example:

//PS: To be regarded as pseudocode at best, as lots of Qt boilerplate
//    and error handling code has been left out, and lots of bugs are left in :-)

struct MyInterface{
  virtual void doStuff()=0;
 signals:
  void someSignal();
}

struct MyImpX:public MyInterface{
  void doStuff(){
    qDebug()<<"MyImpX";
    if((random()%100)<5){
      emit someSignal();
    }
  }
}

struct MyImpY:public MyInterface{
  void doStuff(){
    qDebug()<<"MyImpY";
    if((random()%100)<10){
      emit someSignal();
    }
  }
}

struct MyWorker{
  QTimer t;
  MyInterface *inst=0;
  MyWorker(MyInterface *inst):
    inst(inst)
  {
    connect(&t,SIGNAL(timeout()),this,SLOT(doStuff()));
    t.start(100);
  }
  void setNewInstance(MyInterface *inst){
    this->inst=inst;
  }
  void doStuff(){
    if(0!=inst){
      inst->doStuff();
    }
  }
}


struct MyConsumer{
  public slots:
  void handleIt(){
    qDebug()<<"Handling signal";
  }
}



void main(){
 QApplication app;
 MyInterface *inst=new MyImpX();
  MyWorker con(inst);
  MyConsumer i,j,k,l;
  //In this example all the connects are in one place, but
  //in reality they are called from several locations that
  //Are hard to control.
  connect(inst,SIGNAL(someSignal()),&i,SLOT(handleIt()));
  connect(inst,SIGNAL(someSignal()),&j,SLOT(handleIt()));
  connect(inst,SIGNAL(someSignal()),&k,SLOT(handleIt()));
  connect(inst,SIGNAL(someSignal()),&l,SLOT(handleIt()));
  //[ ... At this point some time passes where the signal is working ]
  //Now the instance changes, so the old connections are lost.
  con.setNewInstance(new MyImpY());
  delete inst;
  inst=0;
  //[ ... At this point some time passes where the signal is NOT working ]
 app.exec();
}
Mr. Developerdude
  • 9,118
  • 10
  • 57
  • 95

1 Answers1

1

You could try to implement something based on this question, but I think that'll be hacky at best.

So, instead, you could have a proxy object, which does not get changed, and which can change its connections when the actual object changes. For this, you should probably use signal-signal connections, though you could also write slots which emit signals. Question has pseudocode, so here's some pseudocode as well, to demonstrate the principle.

class MyInterfaceSignalProxy : public MyInterface { 
//...
public:
    void reconnect(MyInterface *newObj, MyInterface *oldObj=0) {
        if(oldObj) disconnect(oldObj, 0, this, 0); // disconnect old connections
        connect(newObj, SIGNAL(someSignal()), this, SIGNAL(someSignal()));
    }

signals:
    void someSignal();
}

Of course you could remove the oldObj parameter, and for example store the currently connected object as private variable, or just not care about disconnection earlier connectios (for example if oldObj will be deleted or otherwise disconnected elsewhere).

And then your main would start something like:

void main(){
  QApplication app;

  MyInterfaceSignalProxy proxy; 
  MyConsumer i,j,k,l;
  connect(&proxy,SIGNAL(someSignal()),&i,SLOT(handleIt()));
  connect(&proxy,SIGNAL(someSignal()),&j,SLOT(handleIt()));
  connect(&proxy,SIGNAL(someSignal()),&k,SLOT(handleIt()));
  connect(&proxy,SIGNAL(someSignal()),&l,SLOT(handleIt()));

  MyInterface *inst=new MyImpX();
  proxy.reconnect(inst);
  //....

  MyInterface *inst2=new MyImpY();
  proxy.reconnect(inst2, inst);
  delete inst; // whatever
Community
  • 1
  • 1
hyde
  • 60,639
  • 21
  • 115
  • 176
  • Thanks for an good answer! I was not aware that signal-to-signal connections was possible, that will probably prove handy. I actually solved this after realizing that the emit keyword may be used to emit signals on behalf of any object, not just "this". So in my app I put all the signals on a proxy object and connect to that and then simply do "emit proxy.signal" from wherever the signal is sent. – Mr. Developerdude Oct 28 '14 at 21:53