从另一个指针指向函数的指针

Posted

技术标签:

【中文标题】从另一个指针指向函数的指针【英文标题】:Pointer to function from another pointer 【发布时间】:2020-01-12 17:36:34 【问题描述】:

我是 C++ 新手,我正在尝试在我的 Arduino 项目中制作一个通用开关(即设备,而不是 C++ 语句),该开关可用于闪烁灯、打开和关闭哔哔声等。

我可以创建一个可切换接口并在我想要“切换”的类中实现它。但是因为我这样做是为了学习,并且我看到了 C++ 中的指针函数能力(这对我来说是新的,因为我来自 C# 和 Java),我认为这将是一个尝试的好机会...

问题是我只能在我的代码中传递该函数,如果它是一个本地函数,但如果我尝试从另一个对象(例如 LED)传递函数,它将不起作用。

一些代码来说明问题。这是switch.cpp,它在其构造函数中接收OnOff 函数,并且它有一个在Arduino ino 主类的循环方法中调用的更新方法:

auto_switch.cpp

using switch_function = void(*)();
auto_switch::auto_switch(const switch_function on_function, const switch_function off_function, const int max_speed_count)

    //sets all variables...


void auto_switch::update(const unsigned long millis)

    //turn switch on and off...


这是我的 ino 文件

ino file

#include <Arduino.h>
#include "led.h"
#include "auto_switch.h"

led* main_led;
auto_switch* led_switch;
int slow_speed;

//ugly code
void turn_led_on()

    main_led->turn_on();


//ugly code
void turn_led_off()

    main_led->turn_off();


void setup() 
    main_led = new led(2, 3, 4, true, color::white);

    //ugly code
    led_switch = new auto_switch(turn_led_on, turn_led_off, 3);

    slow_speed = led_switch->add_speed(100, 100, 3, 1000);
    led_switch->set_active_speed(slow_speed);
    led_switch->turn_on();


void loop() 
    led_switch->update(millis());

它可以工作,但我必须创建一个本地函数(turn_led_onturn_led_off)才能将内部函数作为参数分配给 auto_switch 构造函数,这些部分是我编写的 //ugly code

我想做这样的事情,中间没有胶水代码:

//doesn't work
led_switch = new auto_switch(main_led->turn_on, main_led->turn_off, 3);

有可能吗?我已经阅读了一些关于指向函数的静态指针和一些有助于解决此问题的 std 函数的内容,如果我做对了,在这种情况下胶水代码是必要的,这样编译器就可以知道我猜的函数来自哪里(来自哪个对象( >

无论如何,这有意义吗,可以使用指向函数的指针来完成,还是应该创建一个接口或不同的东西?

【问题讨论】:

这能回答你的问题吗? Function pointer to member function @Scheff 感谢您的建议,我已经阅读了有关成员函数的信息,但我相信它不会使开关变得通用,对吧?我的意思是,开关只适用于成员类型,所以我需要为每个开关目标(如 LED、哔哔声等)提供一个开关类,对吗? 如果你写“switch”,你的意思不是声明switch,不是吗?抱歉,这有点令人困惑。但是,如果您正在寻找更通用的东西,它可以保存指向普通函数的指针以及成员函数指针(带有对象),我建议查看std::function。 如果是这样的话,我猜最好使用界面来代替?! @TedLyngmo 很高兴知道这一点,那我试试,谢谢你的信息 【参考方案1】:

在决定如何做之前,问题是你想做什么以及为什么。因为,使用简单的 C++ 习语也许有更好的选择。

选项 1:多态的特化

你想专门化你的 switch 的一些功能,而不是调用 auto_switch 的函数,而是调用 dome 更专门的函数?

在这种情况下你不会这样做:

//doesn't work
led_switch = new auto_switch(main_led->turn_on, main_led->turn_off, 3);

但是你会依赖于基类中的虚函数的多态性:

class auto_switch 
...
    virtual void turn_on();  
    virtual void turn_off(); 
...
; 

并为 LED 编写一个专门的类:

class led_witch : public auto_switch 
...
    void turn_on() override;  
    void turn_off() override; 
...
; 

其实编译器会在后台生成一些函数指针,但你不必关心:

auto_switch s1=new auto_switch(...); 
auto_switch s2=new led_switch(...);   // no problem !! 

s1->turn_on();     // calls auto_switch::turn_on() 
s2->turn_on();     // calls led_switch::turn_on() since the real type of s2 is led_switch 

但是,如果每个对象的行为在对象的真实类的基础上是动态的,则同一类的对象共享在编译时预定义的行为。如果这不正确,请转到下一个选项。

选项2:成员函数指针

另一个对象的函数只能在该对象在手时调用。因此,拥有一个指向 led 函数的函数指针是不够的:您还需要知道它应该应用在哪个 led 上。

这就是为什么成员函数指针不同并且有些约束:你只能调用你的成员函数指针的类的函数。如果多态性就足够了(即,如果派生类具有在基类中已经预见到的函数的不同实现),那么你很幸运。如果你想使用一个只存在于派生类而不存在于基类中的函数,它将无法编译。

这里是auto_swith 的简化版本:我提供了一个函数,但也提供了一个指向必须调用该函数的对象的指针:

class auto_switch
    void (led::*action)(); 
    led *ld; 
public: 
    auto_switch(void(led::*a)(), led*l) : action(a), ld(l) 
    void go ()  (ld->*action)(); 
; 
// usage:  
auto_switch s(&led::turn_off, &l1);
s.go(); 

Online demo

选项 3:功能性方式(可能这就是您要找的吗?)

另一种变体是使用标准函数库来绑定成员函数和将在其上执行它的对象(以及任何需要的参数):

class auto_switch
    std::function<void()> action; 
public: 
    auto_switch(function<void()>a) : action(a) 
    void go ()  action(); 
; 

在这里你可以绑定任何东西:任何类的任何函数:

auto_switch s(bind(&led::turn_off, l1));
s.go(); 
auto_switch s2(bind(&blinking_led::blink, l2));
s2.go(); 

Online demo

选项 4:命令模式

现在,如果您想在打开和关闭开关时对对象执行某些操作,但您需要完全的灵活性,您只需实现 command pattern :这可以让您在任何物体。你甚至不需要函数指针。

【讨论】:

哇,首先感谢您抽出宝贵时间,这是一个非常详细的答案...我将尝试评论您告诉我的选项:1:在这种情况下,我们将专注于auto_switch,我的想法不是高度专业化,而是一个通用开关,只有一种行为可以切换多个对象......基本上是命令模式行为(我最终还是这样做了)2:如果我理解正确,就这样做auto_switch 类与 led 类高度耦合的方式,当然在某些情况下这是完全有效的,但在我的情况下,我想要我的通用开关...... 3:我相信功能性的方式也会让我得到结果,但是因为我已经读过我应该避免在 arduino 上进行动态内存分配,这让我避免了这条路线,但我会尝试它也用于学习目的。 4:正是我想要的行为......但因为我正在学习 cpp 我想“指针,为什么不呢?”我最终使用了该模式,但是由于我是第一次学习 cpp,所以我想使用指针的方式来做一些不同的事情来了解它是如何工作的,我被卡住并试图让它工作,但现在我没有'认为它不是最好的方法...... summarizing... 我试图避免使用命令模式的方式来尝试使用函数指针学习新东西(因为我习惯使用的语言没有这个选项),但我认为我可以通过简单地使用指向函数的指针来实现相同的结果,而无需强制其他类实现我的命令接口,这将是一个双赢……如果我做对了,实现这一目标的方法是使用选项 3 和更简单的方法方式将是选项 4,与我的命令界面有一些耦合......再次感谢您的帮助@Christophe

以上是关于从另一个指针指向函数的指针的主要内容,如果未能解决你的问题,请参考以下文章

指向模板类成员函数的函数指针

如何从另一个方法调用指向方法的指针

指向类方法的函数指针作为参数

如何从递归函数中编辑指向列表节点的指针?

如何从另一个类调用指向成员的函数? [复制]

如何定义指向函数的指针?