[英]Method of one class as callback from another
I will describe my problem the simplest as I can. 我将尽可能简单地描述我的问题。
What is my issue: 我的问题是什么:
I have frist class as a singleton: 我有单身人士的第一课:
class CTimer1
{
public:
static CTimer1 * getInstance(); //This gives me pointer to instance
void setChannelA(uint8_t compareValue);
private:
//Cnstructors
CTimer1(); //Prevent consttuction but allow in getInstance
CTimer1(const CTimer1&); //Prevent construction by copying
CTimer1& operator=(const CTimer1&); //Prevent assigment
~CTimer1(); //Prevent unwanted destruction
static CTimer1 * timerInstance;
static bool isCreated;
};
And here is second class where I would like to have possibility to call setChannelA
method from CTimer1
class as a setPwm
method from CServo
class: 这里是第二类,我想有可能调用
setChannelA
从方法CTimer1
类作为setPwm
从方法CServo
类:
class CServo {
public:
CServo();
~CServo();
public:
//public methods
void registerPwmTimer(void (*callback)(uint8_t u8_buffer));
void (*setPwm)(uint8_t u8_buffer); //As this method I would like to call setChannelA from CTimer1 class
};
Here is registerPwmTimer
method: 这是
registerPwmTimer
方法:
void CServo::registerPwmTimer(void (*callback)(uint8_t u8_buffer))
{
setPwm = callback;
}
Then I have tried to assign pointer to this method as a following: 然后,我尝试将指针分配给此方法,如下所示:
int main()
{
CTimer1 * timer1 = CTimer1::getInstance();
CServo servo1();
servo1.registerPwmTimer(timer1->setChannelA);
servo1.setPwm(10); //This is example how I want to call setChannelA method
while(1)
{
}
}
I have error: 我有错误:
error: no matching function for call to 'CServo::registerPwmTimer(<unresolved overloaded function type>)'
What is important: 重要的是:
I can't use std::function
because this is some part of code in C++ for embedded device, so I need to save memory consumption. 我不能使用
std::function
因为这是C ++中嵌入式设备代码的一部分,因此我需要节省内存消耗。 Is there any way that I will be able to achieve this effect? 有什么办法可以达到这种效果? If ony one possibility to do this is ot use some std library please for answers too.
如果只有一种可能是这样做,也请使用一些标准库。 Thanks for your help.
谢谢你的帮助。
Your problem is that a function pointer necessarily has to point to a static function. 您的问题是函数指针必须必须指向静态函数。 When you invoke an instance function (a method) there is a hidden first argument, which is the object on which the function was invoked.
当您调用实例函数(方法)时,会有一个隐藏的第一个参数,即在其上调用该函数的对象。 (This hidden argument is available as
this
within the function's definition.) (这个隐藏参数是可以作为
this
函数的定义。)
Your CServo::registerPwmTimer()
function signature is simply incompatible with invocation of a member function; 您的
CServo::registerPwmTimer()
函数签名与成员函数的调用完全不兼容。 function pointers alone do not provide a way to bind an argument to the pointer, so even if you could convey the member function pointer using a (free) function pointer type, the hidden this
argument could not be determined when the function pointer was invoked. 仅函数指针不能提供将参数绑定到指针的方法,因此,即使您可以使用(自由)函数指针类型来传递成员函数指针,也无法在调用函数指针时确定隐藏的
this
参数。
To put it another way, it would fail for the same reason that trying CTimer1::setChannelA(0)
would fail -- you want to invoke that method, but you haven't communicated which object on which to invoke it. 换句话说,它会以与尝试
CTimer1::setChannelA(0)
失败相同的原因而失败-您想要调用该方法,但尚未传达在哪个对象上调用它。
Change the signature of CServo::registerPwmTimer
to accept an std::function
object instead of a raw function pointer. 更改
CServo::registerPwmTimer
的签名以接受std::function
对象,而不是原始函数指针。 std::function
objects can be constructed from function pointers, but they can also be constructed from lambdas, and some standard library functions return function objects: std::function
对象可以从函数指针构造,但是它们也可以从lambda构造,并且某些标准库函数返回函数对象:
void registerPwmTimer(std::function<void(uint8_t)>);
Now, you can use std::bind
to create a new function that binds the object instance to the member function pointer: 现在,您可以使用
std::bind
创建一个新函数,该函数将对象实例绑定到成员函数指针:
servo1.registerPwmTimer(std::bind(&CTimer1::setChannelA, timer1));
Note that std::bind
does not extend the lifetime of the object pointed to by timer1
. 请注意,
std::bind
不会延长timer1
指向的对象的生存期。 If the returned function is invoked after that object is destructed, the result is undefined behavior. 如果在销毁该对象之后调用返回的函数,则结果将是未定义的行为。
Another alternative would be to accept both an instance and a pointer to a member function. 另一种选择是接受实例和指向成员函数的指针。 The problem with this approach is it requires using templates:
这种方法的问题在于它需要使用模板:
template <typename T>
void registerPwmTimer(void (T::*)(uint8_t), T&);
This isn't bad in itself, but what you'll wind up doing is creating a polymorphic wrapper class so that you can insert this into your callback list alongside other callbacks that don't share the same T
. 这本身并不是一件坏事,但是您最终要做的是创建一个多态包装器类,以便您可以将其与其他不共享
T
回调一起插入到回调列表中。 At that point, you're just recreating std::function
, since std::function
already serves the purpose of being a polymorphic wrapper around callable things. 到那时, 您只是在重新创建
std::function
,因为std::function
已经实现了成为可调用事物周围的多态包装的目的。
To illustrate the mess of implementing a polymorphic callable wrapper yourself, here is a very light example. 为了说明自己实现多态可调用包装器的麻烦,这是一个非常简单的示例。 I will show the declarations of a set of these types, and link to an example implementation.
我将显示一组这些类型的声明,并链接到示例实现。
This is the base type, with a pure virtual operator()
that serves as the invocation operation. 这是基本类型,具有纯虚拟的
operator()
作为调用操作。
class poly_callable
{
public:
virtual void operator()(int) const = 0;
};
Now we have a type for function pointers (also works with pointer-to-functor): 现在,我们有了函数指针的类型(也适用于指向指针的函数):
template <typename T>
class fn_poly_callable : public poly_callable
{
public:
typedef T fn_type;
fn_poly_callable(T);
virtual void operator()(int) const;
private:
T fn;
};
And one for member functions -- oh, but const
member functions and non- const
member functions are not interchangeable, so we need an extra template parameter for that: 还有一个用于成员函数-哦,但是
const
成员函数和非const
成员函数不可互换,因此我们需要一个额外的模板参数:
template <typename T, typename M = void (T::*)(int)>
class member_poly_callable : public poly_callable
{
public:
typedef T object_type;
typedef M member_fn_type;
member_poly_callable(member_fn_type, object_type&);
virtual void operator()(int) const;
private:
member_fn_type mfn;
object_type& target;
};
Plus we'll want some helper functions to allow the compiler to infer the template types. 另外,我们将需要一些帮助函数来允许编译器推断模板类型。 One for function pointers:
一种用于函数指针:
template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(T fn)
{
return std::unique_ptr<poly_callable>(new fn_poly_callable<T>(fn));
}
Two for member functions ( const
and non- const
): 两个用于成员函数(
const
和non- const
):
template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(void (T::*mfn)(int), T& target)
{
return std::unique_ptr<poly_callable>(new member_poly_callable<T>(mfn, target));
}
template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(void (T::*mfn)(int) const, T& target)
{
return std::unique_ptr<poly_callable>(new member_poly_callable<T, void (T::*)(int) const>(mfn, target));
}
If you want to see it all in action, I made a "simple" and working example . 如果您想看到所有功能,我举了一个“简单”的示例 。
So... just use std::function
. 所以...只需使用
std::function
。 There's no reason to reinvent this stuff. 没有理由重新发明这些东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.