C++:将指向一个对象的成员函数的指针存储在另一个对象中
C++: Store pointer to a member function of an object in another object
我有一个class,它会在某些情况下调用用户指定的函数。因此 class 有一个方法 void setExternalPostPaintFunction(void(*function)(QPainter&));
可以用于 "register" 一个函数。然后将在那个时候调用此函数:
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
时被推导出来,因此我不能有一个依赖的成员变量在这种类型上,因为在创建对象时必须知道我的成员变量的类型,除此之外它不能改变,但是在分配新函数的情况下它必须知道它可能是不同类型的对象。
那么正确的方法是什么,或者有什么方法吗?我不太适合模板和函数指针,所以我可能忽略了一些东西。
另一个选择当然是创建一个仿函数 class 和一个可以在派生 class 中覆盖的虚拟成员函数,然后传递 + 存储该类型的对象指针而不是函数指针。但如果可能的话,我会更喜欢我的方法。
编辑:解决方案
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;
};
如您所见,指向 function/member 函数的指针现在存储在 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;
}
在 class 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);
很有魅力。
您可以使用 std::function
:
class A {
public:
//PostPaintFun can be anything which acts as a function taking a QPainter&
//Could be a lambda, function pointer, functor, etc.
using PostPaintFun = std::function<void(QPainter&)>;
void setExternalPostPaintFunction(PostPaintFun fun);
private:
//Names beginning with an underscore are reserved, don't use them
//Ending with an underscore is fine
PostPaintFun fun_;
bool externalPostPaintFunctionAssigned_;
};
现在您可以像这样使用成员函数了:
struct B
{
void exec(QPainter&) const;
};
void foo() {
B b;
a.setExternalPostPaintFunction(
[b] (QPainter& p) {b.exec(p);}
);
}
//or inside B
void B::foo() {
a.setExternalPostPaintFunction(
[this] (QPainter&p) {this->exec(p);}
);
}
我不得不说我更喜欢 TartanLlama 的回答,但这里有一些对您有用的东西。
这可能需要一些工作,但我相信你会明白的。
struct IFunctionHolder {}; // Used for pointing to any FunctionHolder
typedef IFunctionHolder* functionHolder_ptr; // Alias for IFunctionHolder* .
template<typename Function> // The template for the actual function holders.
struct FunctionHolder: public IFunctionHolder
{
Function function;
};
class A {
public:
template <typename T>
void setExternalPostPaintFunction(void(T::*function)(QPainter&), T* object);
private:
functionHolder_ptr *function_holder; // This memeber can hold eny instantiation of template<> FunctionHolder.
// Instantiate this member wen calling setExternalPostPaintFunction
bool _externalPostPaintFunctionAssigned;
};
你可以有这样的代码:
A some_a;
void some_a.setExternalPostPaintFunction(&SomeInstance::some_fnunction); // Here take place the instantiation of FunctionHolder.
some_a.function_holder.function(some_painter);
我有一个class,它会在某些情况下调用用户指定的函数。因此 class 有一个方法 void setExternalPostPaintFunction(void(*function)(QPainter&));
可以用于 "register" 一个函数。然后将在那个时候调用此函数:
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
时被推导出来,因此我不能有一个依赖的成员变量在这种类型上,因为在创建对象时必须知道我的成员变量的类型,除此之外它不能改变,但是在分配新函数的情况下它必须知道它可能是不同类型的对象。
那么正确的方法是什么,或者有什么方法吗?我不太适合模板和函数指针,所以我可能忽略了一些东西。
另一个选择当然是创建一个仿函数 class 和一个可以在派生 class 中覆盖的虚拟成员函数,然后传递 + 存储该类型的对象指针而不是函数指针。但如果可能的话,我会更喜欢我的方法。
编辑:解决方案
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;
};
如您所见,指向 function/member 函数的指针现在存储在 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;
}
在 class 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);
很有魅力。
您可以使用 std::function
:
class A {
public:
//PostPaintFun can be anything which acts as a function taking a QPainter&
//Could be a lambda, function pointer, functor, etc.
using PostPaintFun = std::function<void(QPainter&)>;
void setExternalPostPaintFunction(PostPaintFun fun);
private:
//Names beginning with an underscore are reserved, don't use them
//Ending with an underscore is fine
PostPaintFun fun_;
bool externalPostPaintFunctionAssigned_;
};
现在您可以像这样使用成员函数了:
struct B
{
void exec(QPainter&) const;
};
void foo() {
B b;
a.setExternalPostPaintFunction(
[b] (QPainter& p) {b.exec(p);}
);
}
//or inside B
void B::foo() {
a.setExternalPostPaintFunction(
[this] (QPainter&p) {this->exec(p);}
);
}
我不得不说我更喜欢 TartanLlama 的回答,但这里有一些对您有用的东西。
这可能需要一些工作,但我相信你会明白的。
struct IFunctionHolder {}; // Used for pointing to any FunctionHolder
typedef IFunctionHolder* functionHolder_ptr; // Alias for IFunctionHolder* .
template<typename Function> // The template for the actual function holders.
struct FunctionHolder: public IFunctionHolder
{
Function function;
};
class A {
public:
template <typename T>
void setExternalPostPaintFunction(void(T::*function)(QPainter&), T* object);
private:
functionHolder_ptr *function_holder; // This memeber can hold eny instantiation of template<> FunctionHolder.
// Instantiate this member wen calling setExternalPostPaintFunction
bool _externalPostPaintFunctionAssigned;
};
你可以有这样的代码:
A some_a;
void some_a.setExternalPostPaintFunction(&SomeInstance::some_fnunction); // Here take place the instantiation of FunctionHolder.
some_a.function_holder.function(some_painter);