如何使用指向C++方法的指针

How can I use pointer to C++ method?

本文关键字:方法 指针 C++ 何使用      更新时间:2023-10-16

我想在wake_event中使用类方法指针,如下所示,但是编译错误,我不想使用静态成员和方法,因为此类可能有多个实例,可以吗? 我可以修改我的源吗?

class UncouplerController {
private:
    TouchSensor *touchSensor;
public:
    wakeup_t touched(wakeup_t data) {
        return UncouplerController::touchSensor->pressed();
    }
   const void uncoupling() {
       wait_event(&touched, 0);
   }
}

编译错误如下

/usr/local/bin/h8300-hitachi-hms-g++ -DCXX -fno-rtti -fno-exceptions -O2 -fno-builtin -fomit-frame-pointer -Wall -I/brickos/include -I/brickos/include/lnp -I. -I/brickos/boot  -c rcx1.C -o rcx1.o
In file included from rcx1.H:27,
                 from rcx1.C:21:
UncouplerController.H: In function `static wakeup_t UncouplerController::untouched(long unsigned int)':
UncouplerController.H:38: member `UncouplerController::touchSensor' is non-static but referenced as a static member
UncouplerController.H:62: at this point in file
UncouplerController.H:63: warning: control reaches end of non-void function `UncouplerController::untouched(long unsigned int)'
UncouplerController.H: In method `const void UncouplerController::uncoupling()':
UncouplerController.H:74: converting from `wakeup_t (UncouplerController::*)(long unsigned int)' to `wakeup_t (*)(long unsigned int)'
UncouplerController.H: In method `const void UncouplerController::coupling()': 
UncouplerController.H:99: converting from `wakeup_t (UncouplerController::*)(long unsigned int)' to `wakeup_t (*)(long unsigned int)'
UncouplerController.H: At top level:
UncouplerController.H:112: `class TouchSensor * UncouplerController::touchSensor' is not a static member of `class UncouplerController'

这里要知道的是,指向成员函数的指针与指向(独立)函数的指针不同。不同之处在于,所有成员函数都有一个隐藏的第一个参数,该参数是函数中的this指针。因此,您需要有一个对象的实例才能实际调用成员函数指针。

只有static成员函数没有这个隐藏的第一个参数,因为它们没有this指针(静态成员函数用于整个类,而不是特定实例),因此可以用作普通函数指针。


有三种使用成员函数指针的方法。

  • 第一种是使用静态成员函数,并为其提供一个参数,该参数将作为指向实例的指针。当然,这只有在系统允许您将额外的参数传递给函数指针时才有效。如果(我只是在这里猜测)wait_event的第二个参数是这样的"userdata"指针,那么这可以用于它:

    wait_event(&staticTouched, this);
    

    然后你创建一个静态成员函数来调用真正的函数:

    static void staticTouched(void* instance)
    {
        static_cast<UncouplerController*>(instance)->touched();
    }
    
  • 第二种方法是,如果wait_event是类的成员,在这种情况下,它在调用 member 函数时实际上可以使用自己的this指针:

    void wait_event(void (UncouplerController::*func)(), ...)
    {
        // Do stuff...
        (this->func)();  // Call the member function pointer
    }
    
  • 第三种方法是使用新的 C++11 std::function类,而不是成员函数指针。这将使事件处理系统更加通用,因为std::function可用于存储普通函数、静态成员函数、非静态成员函数和 lambda 表达式。除此之外,它与第二种情况非常相似:

    void wait_event(std::function<void()> func, ...)
    {
        // Do stuff...
        func();  // Call the function object
    }
    

    然后,要使用成员函数指针调用wait_event,请使用std::bind

    wait_event(std::bind(&UncouplerController::touched, this), 0);
    

如果wait_event函数是轨道中的轻量级竞赛所指出的函数,则不能使用成员函数指针。我上面列表中的第一种情况是错误的,因为第二个参数是完全不同的东西。

这是我的代码,它可以工作。

class UncouplerController {
private:
    static TouchSensor *touchSensor;
public:
    UncouplerController(Sensor::Port sensorPort) {
        touchSensor = new TouchSensor(sensorPort);
    }
    ~UncouplerController() {
        delete touchSensor;
    }
    static wakeup_t touched(wakeup_t data) {
        return UncouplerController::touchSensor->pressed();
    }
    static wakeup_t untouched(wakeup_t data) {
        return !UncouplerController::touchSensor->pressed();
    }
    const void uncoupling() {
        wait_event(&UncouplerController::touched, 0);
        delay(UNCOUPLING_TIME1);
    }
    const void coupling() {
        wait_event(&UncouplerController::touched, 0);
        wait_event(&UncouplerController::untouched, 0);  
        delay(COUPLING_TIME);
    }
};
TouchSensor *UncouplerController::touchSensor;

我想知道如果没有使用静态成员或函数,并将它们全部移出类,我可以得到相同的结果!! 有人告诉我哪种方式更好吗? 感谢您的帮助。

我同意约阿希姆的观点。另一方面,我会给你一些代码的提示,让我知道是否适合你。

更改行:

return UncouplerController::touchSensor->pressed();

由:

return this->touchSensor->pressed();

wait_event正在检查一个独立函数,您正在传递一个作为类成员的函数,这就是为什么输出错误中的以下行

UncouplerController.H:74: converting from `wakeup_t (UncouplerController::*)(long unsigned int)' to `wakeup_t (*)(long unsigned int)'

因此,您可以重新定义 touched 以返回一些指向独立函数的指针,并使用参数更改其行为。或者,将wakeup_t声明为独立函数,并使其成为类的好友。第二个看起来要容易得多。

让我知道是否有效。如果您发布更多代码,也许可以帮助您更多。

另一种方法是使用关键字"reinterpret_cast",但我不推荐它。

好吧,您可以尝试以下方法:

// Define the type expected by  "wait_event"
typedef wakeup_t (*wake_func_ptr) (wakeup_t data);

class UncouplerController {
private:
    TouchSensor *touchSensor;
public:
    // Member for pointing the target functions.
    wake_func_ptr touched;
    wake_func_ptr untouched;
    UncouplerController(Sensor::Port sensorPort)
    {
        // This will rise a lot of warnings.
        // I strongly not recomend to do this.
        // But it seems to be a solution.
        touched = reinterpret_cast<wake_func_ptr>(&UncouplerController::touched_func);
        untouched = reinterpret_cast<wake_func_ptr>(&UncouplerController::untouched_func);
        touchSensor = new TouchSensor(sensorPort);
    }

    ~UncouplerController() {
        delete touchSensor;
    }
    wakeup_t touched_func(wakeup_t data) {
        return touchSensor->pressed();
    }
    wakeup_t untouched_func(wakeup_t data) {
        return touchSensor->pressed();
    }

    const void uncoupling() {
        wait_event(touched, 0);
        delay(UNCOUPLING_TIME1);
    }
    const void coupling() {
        wait_event(touched, 0);
        wait_event(untouched, 0);
        delay(COUPLING_TIME);
    }
};
// The purpose of this line isn't clear for me.
TouchSensor *UncouplerController::touchSensor;