c++ - 在同一对象中设置私有(private)变量的回调函数

标签 c++ arduino

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

目前,我的类(class)如下。

在 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 bool 值保持私有(private),因为它不应该被任何其他类修改,所以我使用公共(public) 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;

如有任何建议,我们将不胜感激。

最佳答案

您的问题从此时开始:

startupTimer.setTimeout(5000, endInit);

看起来,您的方法需要获取一个无需任何对象即可调用的函数,因此您必须使用静态函数。

但是在类中定义的静态函数不能从对象访问数据成员!从类中调用静态函数时,根本不涉及任何对象。

如果你不想让你的变量也是静态的,这最终会使所有东西都变成静态的,并且你不能再使用你的类的多个实例,你需要一种方法来绑定(bind)一个对象和一个方法给你的回电。

我不知道您的startupTimer.setTimeout 是如何定义的。但是如果它只是简单地接受一个指向可调用对象的指针,它可以这样写:

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

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

如果您的计时器接口(interface)没有提供向回调中添加一些用户数据,您就没有机会将对象数据设置到回调中。这样的计时器对象接口(interface)几乎没有用。这使得无法使用任何类型的 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 对象)保存到一个列表中,该列表在编译时生成。所以这里的模板提供了第二个参数,它是您要调用的实例的索引。 因为模板提供了一个静态回调方法(forwarder),它本身可以用作对不良设计接口(interface)的回调。如前所述:这是一个非常糟糕的主意。最好使用功能齐全的定时器库!

关于c++ - 在同一对象中设置私有(private)变量的回调函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49191443/

相关文章:

Python读取输出声音未输入

terminal - 清除终端屏幕?

c++ - 不保存任何图像..保存视频帧时

audio - 使用arduino和声音传感器时串行监视器不断说0

c++ - cpp 和 C 中非法除以零异常

c++ - 使用 MatGeoLib 进行 3D 碰撞检测?

c++ - Arduino 方法名称与库函数冲突

python - 所有线程均未与QThread以及QtSerialPort(对于Arduino)和Matplotlib一起运行

c++ - 跟踪重复键 STL 映射?

c++ - 如何在 teamcity CI 中使用 python 构建脚本?