不透明指针 (pimpl) 以及信号和槽
Opaque Pointer (pimpl) and signals and slots
我越来越喜欢 Pimpl idiom(指向真实 class 实现的私有不透明指针)。但是还有一个问题困扰着我。
这个 idiom\design 模式如何处理 public class 中的信号(比如 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
中的所有信号,连接外部 class 的信号?信号量是public可用信号量的两倍有点烦人,当我需要交换实例时也很烦人。
- 我是否将 public 实例作为参数传递给直接调用 public 信号的私有实例
- 我没听说过的另一种结合设计机制?
Do I replicate all signals in the pimpl, connect with signals of the outer class? A bit annoying to have twice as much signals as what is publicly available, also annoying when I need to swap instances.
不,你不需要那样做。
Do I pass the public instance as parameter to the private instance which calls directly the public signals
那也没有必要。
Another design mechanism in conjuction I didn't heard of?
那也没有必要。
假设 my_class::monitorstuff
应该发出信号,我想你只需要:
void my_class::monitorstuff()
{
pimpl->reallymonitorstuff();
emit <<Details of signal>>;
}
pimpl
不需要关心信号或槽。
总的来说,我真的看不出问题所在。 public class 应该将所有调用转发给 impl,包括连接插槽的调用。 impl 包含信号,而不是 public class。例如这里使用 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。
我越来越喜欢 Pimpl idiom(指向真实 class 实现的私有不透明指针)。但是还有一个问题困扰着我。
这个 idiom\design 模式如何处理 public class 中的信号(比如 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
中的所有信号,连接外部 class 的信号?信号量是public可用信号量的两倍有点烦人,当我需要交换实例时也很烦人。 - 我是否将 public 实例作为参数传递给直接调用 public 信号的私有实例
- 我没听说过的另一种结合设计机制?
Do I replicate all signals in the pimpl, connect with signals of the outer class? A bit annoying to have twice as much signals as what is publicly available, also annoying when I need to swap instances.
不,你不需要那样做。
Do I pass the public instance as parameter to the private instance which calls directly the public signals
那也没有必要。
Another design mechanism in conjuction I didn't heard of?
那也没有必要。
假设 my_class::monitorstuff
应该发出信号,我想你只需要:
void my_class::monitorstuff()
{
pimpl->reallymonitorstuff();
emit <<Details of signal>>;
}
pimpl
不需要关心信号或槽。
总的来说,我真的看不出问题所在。 public class 应该将所有调用转发给 impl,包括连接插槽的调用。 impl 包含信号,而不是 public class。例如这里使用 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。