类成员函数指针

9

我正在尝试使用类函数(中断服务例程),

void (ClassName::*fp)(void)=ClassName::FunctionName;

我希望你能够将其附加到Arduino中断引脚,并使用以下类型输入的函数,但这并不起作用。

void attachInterrupt(int, void (*)(void),int);

我该如何做到这一点?中断服务例程(ISR)需要访问私有对象数据,因此我不能在类外创建一个函数。

编译器错误:

ClassName.cpp : : In constructor 'ClassName::ClassName()':
ClassName.cpp : *)()'
ClassName.cpp : *)()' to 'void (*)()' for argument '2' to 'void attachInterrupt(uint8_t, void (*)(), int)'

注意:我正在寻找课堂内的解决方案,并将接受能够向我展示解决方案或展示无法实现的答案。

2
你遇到了一个错误吗?是什么错误? - David G
我正在使用Visual Studio 2012编译器。我会把编译器错误放到我的问题中。 - Flying Swissman
抱歉,一开始是错误的编译器错误,现在已经正确了。 - Flying Swissman
3个回答

8
如果函数不是 static 的,你不能将其作为非成员函数指针传递给接受该指针类型的函数。
注意,一个非 static 成员函数有一个隐式指向 ClassName 的指针作为它的第一个参数,该指针指向调用该成员函数的对象。
struct X
{
    static void foo() { } // Does not have an implicit "this" pointer argument
    void bar() { } // Has an implicit "this" pointer argument
};

int main()
{
    void (*f)() = &X::foo; // OK: foo is static
    void (*g)() = &X::bar; // ERROR! bar is non-static
}

这里,即使使用std::bind()也不起作用,因为结果无法转换为函数指针。Lambda表达式可以转换为函数指针,但仅限于非捕获的情况(并且此处的lambda表达式需要捕获对象以调用成员函数)。

因此,唯一(丑陋)的解决方法是拥有一个全局适配器函数,该函数在通过全局指针变量访问对象上调用成员函数。在调用函数之前设置全局指针变量:

struct X
{
    void bar() { }
};

void function_taking_a_function_pointer(void (*f)())
{
    // Do something...
    f();
}

X* pX = nullptr;
void bar_adapter()
{
    pX->bar();
}

int main()
{
    X x; // Some object I want to invoke the member function bar() on...

    pX = &x; // Set the global pointer and invoke the function...
    function_taking_a_function_pointer(bar_adapter);
}

如果您希望的话,可以将bar_adapter转换为一个函数模板,通过将指向成员函数的指针作为模板参数传递来使其更加灵活:

template<typename T, void (T::*mf)()>
void adapter()
{
    (pX->*mf)();
}

以下是如何使用它的方法:

#include <iostream>

struct X
{
    void foo() { std::cout << "X::foo()" << std::endl; }
    void bar() { std::cout << "X::bar()" << std::endl; }
};

void function_taking_a_function_pointer(void (*f)())
{
    // Do something...
    f();
}

X* pX = nullptr;

template<typename T, void (T::*mf)()>
void adapter()
{
    (pX->*mf)();
}

int main()
{
    X x; // Some object I want to invoke the member function bar() on...

    pX = &x; // Set the global pointer and invoke the function(s)...

    function_taking_a_function_pointer(adapter<X, &X::foo>);
    function_taking_a_function_pointer(adapter<X, &X::bar>);
}

最后,这里有一个实时示例

2
每个类成员函数都有一个隐式的第一个参数,即this指针,因此您的方法实际上不是没有参数列表 - 它需要一个参数 - 调用它的实例。

好的,谢谢,这很有道理,但并没有解决我的问题。我唯一能做的就是将对象数据公开,并在对象外部创建一个ISR吗?还是有其他方法可以解决这个问题? - Flying Swissman
1
@FlyingSwissman:我在我的回答中提出了一个解决方法。不幸的是,当一个函数接受一个原始函数指针时,很难做很多事情。 - Andy Prowl

0

您可以使用 boost::function<>boost::bind<> 来指向一个类成员函数:

# include <boost/function.hpp>
# include <boost/bind.hpp>
class FunctionClass {
    private:
       double a_;
    public:
       FunctionClass (const double & a): a_(a ){}
       double multWithA (const double & x) const { return a_*x;}
       double operator ()(const double & x) const { return a_*x;}
};

FunctionClass myClass (2.0);
double x = 12.0;
boost :: function <double (FunctionClass *, double)> funcPtr , funcPtr1;
funcPtr =& FunctionClass :: multWithA;
funcPtr1 =& FunctionClass :: operator ();

std :: cout << myClass . multWithA (x) << std :: endl;
std :: cout << funcPtr (& myClass ,x) << std :: endl;
std :: cout << funcPtr1 (& myClass ,x) << std :: endl;

// Bind the function with the class instance
boost :: function <double (double)> funcPtrNew ;
funcPtrNew = boost :: bind (funcPtr ,& myClass ,_1);
std :: cout << funcPtrNew (x) << std :: endl;

2
他不能这样做,他必须传递一个 void (*)(void) 函数指针。(我不是很喜欢Arduino库。) - ipc
1
因为他需要调用void attachInterrupt(int, void (*)(void),int) - ipc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接