一个类的方法作为回调

Method of one class as callback from another

本文关键字:方法 回调 一个      更新时间:2023-10-16

我会尽可能地描述我的问题。

我的问题是什么:

我有一个单身人士:

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;
};

这是我想从CTimer1类调用setChannelA方法为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
};

这是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构造,并且某些标准库函数返回函数对象:

void registerPwmTimer(std::function<void(uint8_t)>);

现在,您可以使用std::bind创建一个将对象实例绑定到成员函数指针的新功能:

servo1.registerPwmTimer(std::bind(&CTimer1::setChannelA, timer1));

请注意,std::bind 不扩展 timer1指向对象的寿命。如果在破坏该对象后调用返回的函数,则结果是未定义的行为。


另一种选择是接受实例和指向成员函数的指针。这种方法的问题在于它需要使用模板:

template <typename T>
void registerPwmTimer(void (T::*)(uint8_t), T&);

这本身并不糟糕,但是您将要做的是创建一个多态性包装器类,以便您可以将其与其他不共享相同T的回调一起插入回调列表中。那时,您只是在重新创建std::function ,因为std::function已经有目的是在可呼叫的事物周围成为多态性包装器。


说明自己实施多态性可调查包装器的混乱,这是一个非常轻的例子。我将显示一组此类类型的声明,并链接到示例实现。

这是基本类型,带有纯虚拟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));
}

如果您想看到这一切,我做了一个"简单"且有效的示例。

所以...只需使用std::function即可。没有理由重新发明这些东西。