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

标签 c++ interface signals qt5 signals-slots

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

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

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

有什么方法可以优雅地做到这一点,还是我必须更改程序的体系结构以保持对一个位置的所有信号连接的控制(大量工作)?

例子:

//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();
}

最佳答案

您可以尝试根据 this question 实现一些东西,但我认为这充其量只是 hacky。

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

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参数,例如将当前连接的对象存储为私有(private)变量,或者只是不关心断开较早的连接(例如如果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

关于c++ - 通过实例交换 Qt5 维护信号连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26599018/

相关文章:

c++ - 我应该考虑网络字节顺序吗?

c++ - 编译器错误的单元测试

c - 我应该如何修改 C 中的 fork() 以使其运行良好?

C++ 格式化字符串宏

c++ - 我可以通过 AF_INET 域套接字连接到 ipv6 地址吗?

c# - 为什么即使 IScreen 实现了 IRenderable,我也无法从 List<IScreen> 转换为 List<IRenderable>?

delphi - 如何查明对象是否支持给定接口(interface)(两个 DLL 之间)

c - C 中的结构问题,使用相同的结构多个源文件

c - 检测 GtkTreeView 行的鼠标移出

Python:信号处理程序的帧参数