C++ 通过实例交换Qt5维护信号连接

C++ 通过实例交换Qt5维护信号连接,c++,interface,signals,qt5,signals-slots,C++,Interface,Signals,Qt5,Signals Slots,在我的Qt5程序中,我有一个带有一些信号的接口 该接口的实现在启动时实例化,信号从程序的不同部分(许多地方)连接到 现在我想删除该实例并创建一个新实例,可能来自另一个实现,并以某种方式维护信号连接,以便所有接收信号的地方都不需要关心实现的更改 是否有任何方法可以优雅地做到这一点,或者我必须改变程序的架构以保持对一个位置上所有信号连接的控制(大量工作) 例如: //PS: To be regarded as pseudocode at best, as lots of Qt boilerplate

在我的Qt5程序中,我有一个带有一些信号的接口

该接口的实现在启动时实例化,信号从程序的不同部分(许多地方)连接到

现在我想删除该实例并创建一个新实例,可能来自另一个实现,并以某种方式维护信号连接,以便所有接收信号的地方都不需要关心实现的更改

是否有任何方法可以优雅地做到这一点,或者我必须改变程序的架构以保持对一个位置上所有信号连接的控制(大量工作)

例如:

//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();
}
//PS:充其量被视为伪代码,就像很多Qt样板一样
//错误处理代码被省略了,许多错误被遗留在:-)
结构MyInterface{
虚空doStuff()=0;
信号:
无效信号();
}
结构MyImpX:公共MyInterface{
void doStuff(){

qDebug()您可以尝试基于实现一些东西,但我认为这充其量只是一种黑客行为

因此,相反,您可以有一个代理对象,它不会被更改,并且可以在实际对象更改时更改其连接。为此,您可能应该使用信号连接,尽管您也可以编写发出信号的插槽。问题有伪代码,所以这里也有一些伪代码,以演示该原理

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();
}
当然,您可以删除
oldObj
参数,例如将当前连接的对象存储为私有变量,或者不关心断开早期连接(例如,如果
oldObj
将被删除或在其他地方断开连接)

然后您的
main
将开始如下操作:

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

谢谢你的好回答!我不知道信号到信号的连接是可能的,这可能会证明很方便。我实际上解决了这个问题,因为我意识到emit关键字可以用来代表任何对象发出信号,而不仅仅是“这个”。所以在我的应用程序中,我把所有信号放在代理对象上,连接到那个对象,然后简单地做无论信号发送到何处,都会发出“emit proxy.signal”。