我有一个FreeRTOS函数xTaskCreate
。简化声明看起来像
typedef void (*TaskFunction_t)( void* );
unsigned xTaskCreate( TaskFunction_t pxTaskCode, void*params );
有两个类:
class Super {
virtual void task(void*params) = 0;
};
class Derived1 : public Super {
virtual void task(void*params){ while(1){ blinkLed(1); delay_ms(333); } }
};
class Derived2 : public Super { ... ;}
在函数init()
中,我选择一个派生类并创建其实例。然后想要创建任务
void init(){
Super *obj = condition ? new Derived1 : new Derived2;
xTaskCreate( obj->task ); // WRONG.
}
UPD。在void*params
的简化声明中添加错过的xTaskCreate
。
答案 0 :(得分:7)
TaskFunction_t
只是一个指向函数的指针 - 因此它不能指向成员函数。只有指向正常功能的指针。或者是静态成员函数。或者没有捕获的lambda。这是我们将利用的最后一个。
您从简化声明中删除的一个论点是context:
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
const char * const pcName,
unsigned short usStackDepth,
void *pvParameters, // <== this one!
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
);
您在参数中提供Super*
并提供一个知道如何处理它的lambda。共:
void init(){
Super *obj = condition ? new Derived1 : new Derived2;
xTaskCreate([](void* o){ static_cast<Super*>(o)->task(); },
..., // other args here
obj,
... // more args
);
}
请注意task()
不应该参数。 void*
是我们要转换为Super*
的上下文。
答案 1 :(得分:0)
在对自己的问题进行了几次实验之后,我更喜欢这种简单的方法,该方法为RTOS任务提供面向对象的函数调用。
//These are not full declaration of class IModule which is fully abstarct so //object that are IModule* are always inherited.
protected:
virtual int InitModule() = 0;
virtual bool PreLoop() = 0;
virtual bool DoLoop() = 0;
virtual bool PostLoop() = 0;
virtual bool DoShutdown() = 0;
//Return if this module implementation requires an RTOS task looping.
virtual bool isFreeRTOSTaskRequired() = 0;
private:
TaskHandle_t *moduleLoopTaskHandle;
bool CreateRTOSTask();
static void TaskStart(void* taskStartParameters);
void TaskLoop();
//END OF PARTIAL decleration
bool IModule::CreateRTOSTask()
{
xTaskCreate(IModule::TaskStart, "NAME", 2048, this, tskNO_AFFINITY, moduleLoopTaskHandle);
return true;
}
void IModule::TaskStart(void *taskStartParameters)
{
IModule *moduleObject = (IModule *)taskStartParameters;
moduleObject->TaskLoop();
}
void IModule::TaskLoop()
{
//TODO Buraya ölçüm koyalım ve bir değişkene yazalım
while (true)
{
ESP_LOGD("IModule::TaskLoop", "%s", "I am alive!");
if (!PreLoop())
{
}
if (!DoLoop())
{
}
if (!PostLoop())
{
}
}
vTaskDelete(NULL);
}
答案 2 :(得分:-1)
更新:见下文。
正如我所能解释的那样here,你可能会侥幸逃脱。很难从你的问题中判断它是否能满足你的所有要求。
typedef void (Super::*TaskFunction_t)( void* );
更新: 我充实了你的例子,结果和代码如下:
XXXXX:~/scratch/member_function_pointer$ bin/provemeright
Condition false
virtual void Derived2::task(void*)
XXXXX:~/scratch/member_function_pointer$ bin/provemeright foo
Condition true because of argument foo
virtual void Derived1::task(void*)
代码(所有一个cpp文件,错误的表单,但证明语法):
#include <iostream>
class Super;
typedef void (Super::*TaskFunction_t)(void*);
unsigned xTaskCreate( TaskFunction_t pxTaskCode, void* params);
bool condition = false;
class Super {
public: virtual void task(void* params) = 0;
};
class Derived1 : public Super {
public: virtual void task(void* params) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
if(params) // Necessary to prevent unused parameter warning
std::cout << "Not Null" << std::endl;
};
};
class Derived2 : public Super {
public: virtual void task(void* params) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
if(params) // Necessary to prevent unused parameter warning
std::cout << "Not Null" << std::endl;
};
};
void init(){
Super *obj = condition ? (Super*)new Derived1 : (Super*)new Derived2;
xTaskCreate( &Super::task , obj);
}
int main(int argc, char **argv)
{
if(argc > 1)
{
std::cout << "Condition true because of argument " << argv[1] << std::endl;
condition = true;
} else {
std::cout << "Condition false" << std::endl;
}
init();
return 0;
}
unsigned xTaskCreate( TaskFunction_t pxTaskCode, void* params)
{
Super *obj = (Super*) params;
(obj->*pxTaskCode)(NULL);
return 0;
}
如果您担心语法是&Super::task
而不是&obj->task
,那么您就会误解虚函数的工作原理。 (事实证明,ISO C ++禁止使用&obj->task
语法,但gcc说它是允许的,所以你不应该强迫它编译,并获得完全相同的结果)
有关要调用的函数的虚拟版本的信息&#39;生活&#39;在对象中,而不是类型系统。 (可能会说得更好,对建议开放,但我认为它得到了一般意义)没有对象就不可能调用成员函数,所以为了利用函数指针,你会有有一个对象在&#39;上调用它。它是确定调用哪个虚函数的对象的类型。所以上面的代码应该实现你想要的任何东西,除非当然,这是一种确定obj指向的对象类型的圆形方式,在这种情况下,它是一个非常复杂的问题去做的方式。
Further Reading特别是在&#34; Kerrek SB&#34的回答中。