【发布时间】:2015-06-16 13:24:25
【问题描述】:
我有一个类会在某些情况下调用用户指定的函数。因此,该类有一个方法void setExternalPostPaintFunction(void(*function)(QPainter&));,可用于“注册”一个函数。这个函数会在那个时候被调用:
class A {
public:
void setExternalPostPaintFunction(void(*function)(QPainter&));
private:
void (*_externalPostPaint)(QPainter&);
bool _externalPostPaintFunctionAssigned;
};
函数指针保存在成员变量_externalPostPaint中。 setExternalPostPaintFunction 的实现如下所示:
void A::setExternalPostPaintFunction(void(*function)(QPainter&)) {
_externalPostPaint = function;
_externalPostPaintFunctionAssigned = true;
}
现在,这适用于正常功能。但是,我还希望能够将指针传递给对象的成员函数。据我所知,在这种情况下,我还必须传递并存储指向对象的指针。但是,我不知道另一个对象将具有哪种类型。所以我想我不得不使用模板。我已经想到了这样的事情:
class A {
public:
template <typename T>
void setExternalPostPaintFunction(void(T::*function)(QPainter&), T* object);
private:
void (T::*_externalPostPaint)(QPainter&); //<- This can't work!
bool _externalPostPaintFunctionAssigned;
};
这样我可以将函数指针和对象指针传递给setExternalPostPaintFunction,并且可能能够在该函数内的对象上调用该函数。但是我无法将它存储在变量 _externalPostPaint 中,因为类型 T 仅在调用函数 setExternalPostPaintFunction 时推导出来,因此我不能拥有依赖于此类型的成员变量,因为在创建对象时必须知道我的成员变量的类型,除此之外它不能更改,但在分配可能是不同类型对象的成员函数的新函数的情况下,它必须知道。
那么正确的方法是什么,或者有什么方法吗?我不太适合模板和函数指针,所以我可能忽略了一些东西。
另一个选择当然是创建一个带有虚拟成员函数的仿函数类,该函数可以在派生类中被覆盖,然后传递 + 存储该类型的对象指针而不是函数指针。但如果可能的话,我会更喜欢我的方法。
编辑:解决方案
TartanLlama 建议使用std::function,让我走上了正轨。以下是我的解决方法:
class A {
public:
template <typename T>
void setExternalPostPaintFunction(T* object, void(T::*function)(QPainter&)) {
_externalPostPaint = std::bind(function, object, std::placeholders::_1);
_externalPostPaintFunctionAssigned = true;
}
void setExternalPostPaintFunction(std::function<void(QPainter&)> const& function);
private:
std::function<void(QPainter&)> _externalPostPaint;
bool _externalPostPaintFunctionAssigned;
};
如您所见,指向函数/成员函数的指针现在存储在std::function<void(QPainter&)> 对象中。优点是,std::function 基本上可以存储任何可调用目标。然后有两个重载:一个可用于任何std::function 对象,它也接受例如一个普通的函数指针(因为预期的 std::function 是从该指针隐式构造的)和一个用于必须在对象上调用的成员函数(为了方便起见更多)。后者作为模板实现。这使用std::bind 在对象(用户传递)上创建该成员函数(用户传递)调用的std::function 对象。
采用std::function 的重载在源文件中实现如下:
void ImageView::setExternalPostPaintFunction(std::function<void(QPainter&)> const& function) {
_externalPostPaint = function;
_externalPostPaintFunctionAssigned = true;
}
在A 类的代码中调用该存储函数现在就这么简单:
//canvas is a QPainter instance
if (_externalPostPaintFunctionAssigned) _externalPostPaint(canvas);
想要将成员函数注册为回调函数的用户只需执行以下操作:
//_imageView is an instance of "A"
//"MainInterface" is the type of "this"
_imageView->setExternalPostPaintFunction(this, &MainInterface::infoPaintFunction);
或者如果它不是成员函数而只是普通函数:
void someFunction(QPainter& painter) {
//do stuff
}
_imageView->setExternalPostPaintFunction(&someFunction);
或者他可以显式创建一个std::function对象并传递它:
std::function<void(QPainter&)> function = [&](QPainter& painter){ this->infoPaintFunction(painter); };
_imageView->setExternalPostPaintFunction(function);
像魅力一样工作。
【问题讨论】:
-
C++11 好吗?
std::function非常适合这种事情。 -
是的,C++ 11 没问题。我去看看。
标签: c++ templates function-pointers member-functions