回调函数在同一个对象中设置私有变量

时间:2018-03-09 10:16:28

标签: c++ arduino

我目前正在开发一些软件来驱动四轴飞行器的ESC。在我的ESC类中,我需要初始化PWM引脚并等待大约5秒以使ESC进行验证,然后再向其发送任何其他节流值。

目前,我的班级如下。

在ESC.h中

class ESC
{

  private:

  int ESCPin;
  bool ESCInitialised;

  //Timer Objects
  SimpleTimer startupTimer;
  void endInit();

  public:
  void initESC(int pin);
  bool isInitialised() const { return ESCInitialised; };
  void setPWM(uint16_t dut);
};

在ESC.cpp中

#include "ESC.h"

void ESC::initESC(int pin){
    ESCInitialised = false;
    ESCPin = pin;
    InitTimersSafe();
    SetPinFrequency(ESCPin, 500); 
    pwmWriteHR(ESCPin,32768); 
    startupTimer.setTimeout(5000, endInit);

}

void ESC::setPWM(uint16_t dut){
  pwmWriteHR(ESCPin, dut);
}

void ESC::endInit(){
    ESCInitialised = true;
}

我希望ESCInitialised布尔值保持私有,因为它不应该被任何其他类修改,所以我使用公共getter方法isInitialised()来返回它。一次性计时器结束后,它应该调用endInit()函数将ESCinitialised bool设置为true,这样主代码就可以确定何时通过新的节流值。

在当前状态下,我收到错误

In static member function 'static void ESC::endInit()':
ESC.h:14: error: invalid use of member 'ESC::ESCInitialised' in static 
member function
   bool ESCInitialised;

非常感谢任何建议。

1 个答案:

答案 0 :(得分:4)

此时您的问题就开始了:

startupTimer.setTimeout(5000, endInit);

看起来,您的方法需要获得一个可以在没有任何对象的情况下调用的函数,因此您必须使用静态函数。

但是,在类中定义的静态函数无法访问对象中的数据成员!简单地说,从类中调用静态函数时不涉及任何对象。

如果你不想使你的变量也是静态的,最终会使一切变为静态,并且你不能再使用类的多个实例,你需要一种方法来绑定一个对象和一个方法你的回调。

我不知道你的startupTimer.setTimeout是如何定义的。但是如果它只是一个指向可调用对象的指针,它就可以这样做:

 startupTimer.setTimeout(5000, [this](){ endInit(); } );

endInit方法必须不再是静态的。

如果您的计时器界面没有提供向回调添加一些用户数据,则您没有机会将对象数据设置为回调。用于计时器对象的这种接口几乎是无用的。这使得无法使用任何类型的OOP。因此,只有一个机会可以列出静态/全局范围辅助函数。 这是非常糟糕的设计

这是一个非常糟糕的工作:

template <typename T, int n>
class UglyObjectCallbackHandler
{
    static T* obj;
    static void(T::*callback)();

    public:

    static void SetObj( T* _obj ) { obj = _obj; }
    static void SetCallback( void(T::* _callback)() ) { callback = _callback; }

    static void ForwardCallback() { (obj->*callback)(); }
};

template <typename T, int n> T* UglyObjectCallbackHandler<T,n>::obj;
template <typename T, int n> void(T::* UglyObjectCallbackHandler<T,n>::callback)();

class A
{
    private:
        int i;
        void(*callback)();
        std::function<void()> callback_func= [this](){ f(); };


    public:
        A( int _i ): i{_i} { }

        void f() { std::cout << "Callback fired" << i << std::endl; }
};

class TimerFake
{   
    private:
        void (*ptr)();

    public:
        void SetCallback( void (*_ptr)() ) { ptr = _ptr; }

        void Fire() { (*ptr)(); }


};

int main()
{
    // multiple client instances possible
    A a(9);
    UglyObjectCallbackHandler<A,0>::SetObj( &a );
    UglyObjectCallbackHandler<A,0>::SetCallback( &A::f );

    A b(77);
    UglyObjectCallbackHandler<A,1>::SetObj( &b );
    UglyObjectCallbackHandler<A,1>::SetCallback( &A::f );

    TimerFake timer0;
    timer0.SetCallback( &UglyObjectCallbackHandler<A,0>::ForwardCallback );

    TimerFake timer1;
    timer1.SetCallback( &UglyObjectCallbackHandler<A,1>::ForwardCallback );

    timer0.Fire();
    timer1.Fire();
}

我们的想法是将多个运行时对象(如ESC对象)保存到编译时生成的列表中。所以这里的模板提供了第二个参数,它是要调用的实例的索引。 因为模板提供了静态回调方法(转发器),所以它可以用来回调设计不良的接口。如上所述:这是一个非常糟糕的主意。更好地使用功能齐全的Timer lib!