我目前正在开发一些软件来驱动四轴飞行器的 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/