一个 class 作为另一个回调的方法
Method of one class as callback from another
我会尽可能简单地描述我的问题。
我的问题是什么:
我第一次 class 单身:
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;
};
这是第二个 class,我希望可以从 CTimer1
class 调用 setChannelA
方法作为 setPwm
方法 CServo
class:
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
};
这里是registerPwmTimer
方法:
void CServo::registerPwmTimer(void (*callback)(uint8_t u8_buffer))
{
setPwm = callback;
}
然后我尝试按如下方式将指针分配给此方法:
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)
{
}
}
我有错误:
error: no matching function for call to 'CServo::registerPwmTimer(<unresolved overloaded function type>)'
重要的是:
我不能使用 std::function
因为这是嵌入式设备的 C++ 代码的一部分,所以我需要节省内存消耗。有什么办法可以达到这种效果吗?如果这样做的唯一一种可能性是不使用某些标准库,请也寻求答案。感谢您的帮助。
您的问题是函数指针必须指向静态函数。当你调用一个实例函数(一个方法)时,有一个隐藏的第一个参数,它是调用该函数的对象。 (此隐藏参数在函数定义中作为 this
可用。)
您的 CServo::registerPwmTimer()
函数签名与成员函数的调用不兼容;单独的函数指针不提供将参数绑定到指针的方法,因此即使您可以使用(自由)函数指针类型传递成员函数指针,隐藏的 this
参数也无法在函数时确定指针被调用。
换句话说,它失败的原因与尝试 CTimer1::setChannelA(0)
失败的原因相同——您想要调用该方法,但您还没有传达在哪个对象上调用它。
更改 CServo::registerPwmTimer
的签名以接受 std::function
对象而不是原始函数指针。 std::function
对象可以从函数指针构造,但它们也可以从 lambdas 构造,一些标准库函数 return 函数对象:
void registerPwmTimer(std::function<void(uint8_t)>);
现在,您可以使用std::bind
创建一个将对象实例绑定到成员函数指针的新函数:
servo1.registerPwmTimer(std::bind(&CTimer1::setChannelA, timer1));
请注意 std::bind
不会 延长 timer1
指向的对象的生命周期。如果在对象被析构后调用 returned 函数,结果是未定义的行为。
另一种选择是同时接受实例和指向成员函数的指针。这种方法的问题是它需要使用模板:
template <typename T>
void registerPwmTimer(void (T::*)(uint8_t), T&);
这本身并不坏,但您最终要做的是创建一个多态包装器 class,这样您就可以将它与其他不共享的回调一起插入到您的回调列表中同样 T
。到那时,你只是在重新创建 std::function
,因为 std::function
已经起到了围绕可调用事物进行多态包装的目的。
为了说明自己实现多态可调用包装器的麻烦,这里有一个非常简单的示例。我将展示一组这些类型的声明,并 link 示例实现。
这是基本类型,具有纯虚拟operator()
作为调用操作。
class poly_callable
{
public:
virtual void operator()(int) const = 0;
};
现在我们有了函数指针的类型(也适用于函子指针):
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;
};
还有一个用于成员函数 -- 哦,但是 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;
};
此外,我们还需要一些辅助函数来允许编译器推断模板类型。一个用于函数指针:
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));
}
两个成员函数(const
和非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));
}
如果你想看到这一切,我做了一个 "simple" and working example。
所以...只需使用 std::function
。 没有理由重新发明这些东西。
我会尽可能简单地描述我的问题。
我的问题是什么:
我第一次 class 单身:
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;
};
这是第二个 class,我希望可以从 CTimer1
class 调用 setChannelA
方法作为 setPwm
方法 CServo
class:
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
};
这里是registerPwmTimer
方法:
void CServo::registerPwmTimer(void (*callback)(uint8_t u8_buffer))
{
setPwm = callback;
}
然后我尝试按如下方式将指针分配给此方法:
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)
{
}
}
我有错误:
error: no matching function for call to 'CServo::registerPwmTimer(<unresolved overloaded function type>)'
重要的是:
我不能使用 std::function
因为这是嵌入式设备的 C++ 代码的一部分,所以我需要节省内存消耗。有什么办法可以达到这种效果吗?如果这样做的唯一一种可能性是不使用某些标准库,请也寻求答案。感谢您的帮助。
您的问题是函数指针必须指向静态函数。当你调用一个实例函数(一个方法)时,有一个隐藏的第一个参数,它是调用该函数的对象。 (此隐藏参数在函数定义中作为 this
可用。)
您的 CServo::registerPwmTimer()
函数签名与成员函数的调用不兼容;单独的函数指针不提供将参数绑定到指针的方法,因此即使您可以使用(自由)函数指针类型传递成员函数指针,隐藏的 this
参数也无法在函数时确定指针被调用。
换句话说,它失败的原因与尝试 CTimer1::setChannelA(0)
失败的原因相同——您想要调用该方法,但您还没有传达在哪个对象上调用它。
更改 CServo::registerPwmTimer
的签名以接受 std::function
对象而不是原始函数指针。 std::function
对象可以从函数指针构造,但它们也可以从 lambdas 构造,一些标准库函数 return 函数对象:
void registerPwmTimer(std::function<void(uint8_t)>);
现在,您可以使用std::bind
创建一个将对象实例绑定到成员函数指针的新函数:
servo1.registerPwmTimer(std::bind(&CTimer1::setChannelA, timer1));
请注意 std::bind
不会 延长 timer1
指向的对象的生命周期。如果在对象被析构后调用 returned 函数,结果是未定义的行为。
另一种选择是同时接受实例和指向成员函数的指针。这种方法的问题是它需要使用模板:
template <typename T>
void registerPwmTimer(void (T::*)(uint8_t), T&);
这本身并不坏,但您最终要做的是创建一个多态包装器 class,这样您就可以将它与其他不共享的回调一起插入到您的回调列表中同样 T
。到那时,你只是在重新创建 std::function
,因为 std::function
已经起到了围绕可调用事物进行多态包装的目的。
为了说明自己实现多态可调用包装器的麻烦,这里有一个非常简单的示例。我将展示一组这些类型的声明,并 link 示例实现。
这是基本类型,具有纯虚拟operator()
作为调用操作。
class poly_callable
{
public:
virtual void operator()(int) const = 0;
};
现在我们有了函数指针的类型(也适用于函子指针):
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;
};
还有一个用于成员函数 -- 哦,但是 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;
};
此外,我们还需要一些辅助函数来允许编译器推断模板类型。一个用于函数指针:
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));
}
两个成员函数(const
和非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));
}
如果你想看到这一切,我做了一个 "simple" and working example。
所以...只需使用 std::function
。 没有理由重新发明这些东西。