指向功能成员的指针

时间:2016-05-02 17:04:48

标签: c++ c++11 member-functions freertos

我有一个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

3 个答案:

答案 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* );

Further Reading

更新: 我充实了你的例子,结果和代码如下:

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的回答中。