我有一个必须实例化对象实例的问题
比我想要的时间更早,因为我需要连接信号
通过一些深所有权的方式,我想出一种方法
存储和转发插槽,以便我可以更紧密地构造对象
到他们的使用网站,而不是作为成员变量。
我的基本问题是我有一个将下载更新的过程
文件放在单独的线程上,并向任何人发送进度信号
感兴趣的。信号本质上是:
typedef boost::signals2::signal<void (double)> DownloadProgress;
假设提到了
progress
函数的实现下面符合这一点;信号本身的性质不是很好
重要(尽管我大部分时候都使用仿函数)。
信号已设置,代码被称为如下所示:
Updater updater;
updater.onDownloadProgress(&progress);
updater.runDownloadTask();
当您调用
updater.runDownloadTask()
时,它将启动UpdaterDownloadTask
,它将启动一个HTTPRequest
并返回一个HTTPResponse
。 HTTPResponse
是与网络层并接收数据并包含
DownloadProgress
信号。这样,我的实现看起来有点像(自下而上HTTPResponse
,缩写为省略方法特别说明):
class HTTPResponse
{
public:
// this will be called for every "chunk" the underlying HTTP
// library receives
void processData(const char* data, size_t size)
{
// process the data and then send the progress signal
// assume that currentSize_ and totalSize_ are properly set
progressSignal_(currentSize_ * 100.0 / totalSize_);
}
void onDownloadProgress(const DownloadProgress::slot_type& slot)
{
progressSignal_.connect(slot);
}
private:
DownloadProgress progressSignal_;
};
class HTTPRequest
{
public:
HTTPRequest() : response_(new HTTPResponse) { }
void onDownloadProgress(const DownloadProgress::slot_type& slot)
{
response_->connect(slot);
}
boost::shared_ptr<HTTPResponse> perform()
{
// start the request, which operates on response_.
return response_;
}
private:
boost::shared_ptr<HTTPResponse> response_;
};
class UpdaterDownloadTask : public AsyncTask
{
public:
DownloadTask() : request_(new HTTPRequest) { }
void onDownloadProgress(const DownloadProgress::slot_type& slot)
{
request_->connect(slot);
}
void run()
{
// set up the request_ and:
request_>perform();
}
private:
boost::shared_ptr<HTTPRequest> request_;
};
class Updater
{
public:
Updater() : downloadTask_(new UpdaterDownloadTask) { }
void onDownloadProgress(const DownloadProgress::slot_type& slot)
{
downloadTask_->onDownloadProgress(slot);
}
void runDownloadTask() { downloadTask_.submit() }
private:
boost::shared_ptr<UpdaterDownloadTask> downloadTask_;
};
因此,我的更新程序必须有一个
UpdaterDownloadTask
实例,该实例是始终存在,其实例为
HTTPRequest
,其实例为HTTPResponse
的实例—只是因为我必须转发插槽从
Updater
(公共(public)API入口点)到HTTPResponse
的连接(信号所属的位置)。
我宁愿像这样实现
UpdaterDownloadTask::run()
:void run()
{
HTTPRequest request;
request.onDownloadProgress(slots_);
#if 0
// The above is more or less equivalent to
BOOST_FOREACH(const DownloadProgress::slot_type& slot, slots_)
{
request.onDownloadProgress(slot);
}
#endif
request.perform();
}
这在HTTPRequest级别会有类似的含义(所以我
在执行请求之前不必构造HTTPResponse)
总体而言,具有强大的RAII语义的数据流更好。我有
以前尝试将
slots_
变量定义为 vector :std::vector<DownloadProgress::slot_type> slots_;
但是,只有当我强制调用者打电话时,我才能使它工作
onDownloadProgress(boost::ref(slot));
。有没有人成功完成此操作,或者对如何进行操作提出了很好的建议
存储和转发除我正在做什么以外的其他信息?
最佳答案
我认为将插槽存储在 vector 中应该可以。如果要摆脱对boost::ref(...)
的需求,可以从&
参数中删除onDownloadProgress
(因为slot_type
是可复制的)。
或者,您可以将信号放入HTTPResponse
内,然后依次将信号发射到HTTPRequest
中,这样做,可以将所有插槽连接到HTTPRequest
中的信号,然后一旦创建了HTTPResponse
,就可以连接到响应信号onDownloadProgress(request.signalname)
。其中signalname
是您的客户的信号。
伪代码:
Request request;
request.onProgress(myProgressBarCallback);
//calls: this.signal.connect(myProgressBarCallback);
request.go();
//calls: Response response;
// and: response.onProgress(this.signal);
希望对您有所帮助。
关于c++ - 如何使用boost::signals2存储和转发插槽?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8936825/