不透明指针(pimpl)、信号和槽

Opaque Pointer (pimpl) and signals and slots

本文关键字:信号 指针 pimpl 不透明      更新时间:2023-10-16

我越来越了解Pimpl习惯用法(指向实际类实现的私有不透明指针)。但是我还有一个问题困扰着我。

这个习惯用法设计模式如何处理公共类中的信号(如boost或qt信号)?

class my_class : public QObject 
{
Q_OBJECT
public:
   void monitorstuff();
signal:
   void needupdate();
private:
    class impl; unique_ptr<impl> pimpl; // opaque type here
};

class my_class::impl {  
    void reallymonitorstuff();
};
my_class::impl::reallymonitorstuff()
{
  ...
  //update required here
  ...
}
void my_class::monitorstuff()
{
  pimpl->reallymonitorstuff();
}
  • 我是否复制pimpl中的所有信号,并与外部类的信号连接?有两倍于公开可用的信号有点烦人,当我需要交换实例时也很烦人。
  • 我是否将公共实例作为参数传递给直接调用公共信号的私有实例
  • 另一个我没听说过的设计机制?

总的来说,我不觉得有什么问题。公共类应该将所有调用转发给impl,包括连接插槽的调用。impl包含信号,而不是公共类。例如这里使用Boost。Signals2:

#include <memory>
#include <boost/signals2.hpp>
#include <iostream>
using signal_type = boost::signals2::signal<void()>;
using slot_type = signal_type::slot_type;
class my_class {
public:
   my_class(); 
   void monitorstuff();
   void connect(const slot_type& slot);
private:
   struct impl; std::unique_ptr<impl> pimpl;
};
struct my_class::impl {
  signal_type signal;
  void reallymonitorstuff();
  void connect(const slot_type& slot){ signal.connect(slot); }
};
void
my_class::impl::reallymonitorstuff() {
  //...
  signal();
  //...
}
void my_class::monitorstuff() {
  pimpl->reallymonitorstuff();
}
void my_class::connect(const slot_type& slot) {
  pimpl->connect(slot);
}
my_class::my_class() : pimpl(std::make_unique<my_class::impl>()){}
int main() {
    my_class mc;
    auto slot = []{ std::cout << "Notified!n"; };
    mc.connect(slot);
    mc.monitorstuff();
}

现场演示。

我想知道你的问题是否更具体到Qt。

我是否复制粉刺中的所有信号,与外部类的信号连接?有两倍于公开可用的信号有点烦人,当我需要交换实例时也很烦人。

不,你不需要那样做。

是否将公共实例作为参数传递给直接调用公共信号的私有实例

那也没必要。

另一个我没听说过的设计机制?

那也没必要。

假设my_class::monitorstuff应该发出信号,我认为你所需要的是:

void my_class::monitorstuff()
{
   pimpl->reallymonitorstuff();
   emit <<Details of signal>>;
}

pimpl不需要关心信号和槽位