【问题标题】:Function pointer in class A to member function from class BA类中的函数指针指向B类的成员函数
【发布时间】:2013-03-11 18:48:53
【问题描述】:

我这几天一直在寻找解决方案。没有找到任何相关的问题足以令人遗憾地回答,所以这是我的问题。 考虑下一个代码:

// dummy class A
class A {
public:
    void aFunction() { // <- this is the function I want to point at
        cout << "aFunction() is called\n";
    }
};

class B {
public:
    template <class Class> // get a function pointer
    void setFunction( void (Class::*func)() ) {
        p_func = func;
    }
    void (*p_func)(); // the function pointer
}

int main() {
    B obj;
    objb.setFunction(&A::aFunction);
    return 0;
}

我在setFunction() p_func = func; 上有一个编译错误:

无法从 'void (__thiscall A::* )(void)' 转换为 'void (__cdecl *)(void)'

而且我似乎无法以任何方式摆脱它。我知道这与那些不可见的this 指针(__thiscall__cdecl)有关,但我不知道如何处理这些。我尝试将成员变量 p_func 也设为类模板(void (Class::*p_func)()),因此它具有相同的结构,但在一个类中包含 2 个类模板似乎是非法的(为什么?),因此不是正确的解决方案。这次编译器抱怨:

不允许有多个模板参数列表

这种方法(没有模板)在全局函数上完美运行(这是我目前使用的解决方法),我看到它在库 (sfgui) 中的使用,所以它应该是完全可能的。

为了了解我想要这个的原因:我正在尝试创建一个按钮。这个按钮应该能够调用我想要的任何功能。现在,我希望它调用我正在制作的动画类的 start() 函数。

ps:我知道这个例子没用,因为我不能运行p_func:函数不是静态的。我仍然需要添加一个对象指针 (setFunction( void (Class::*func)(), Class* )),但这似乎不是问题。而且我知道typedef 可以使函数指针更具可读性,但不适用于类模板。


编辑

经过更多研究后,我认为我需要的答案不是这个问题的答案,而是另一个问题的答案。这一次,我注意到多个template &lt;class Class&gt; 实际上是允许的。但是,成员变量不允许这样做,因为编译器不可能知道他需要使用哪个class,这可能是错误的原因

不允许有多个模板参数列表

这是一个奇怪的描述。无论如何感谢您的帮助,您确实给了我更好的见解。

【问题讨论】:

  • 指向成员函数的指针与指向非成员函数的指针是完全不同的类型——您不能将两者混合使用(并且要使用指向成员函数的指针,您需要类似object.*pmf())。

标签: c++ pointers function-pointers


【解决方案1】:

您不能将指向成员的指针Class::*func 转换为普通函数指针。它们属于不同的类型。

你应该转这个:

void (*p_func)(); // the function pointer

进入这个:

void (class::*p_func)(); // the function pointer

您也可以使用std::function&lt;void()&gt; 并使用boost::bind 来绑定它。

std::function<void()> fun = boost::bind(class::member_fun, args);

编辑

如何让你的 B 类成为模板,这样你就可以做到这一点:

#include<iostream>

class A {
public:
    void aFunction() { // <- this is the function I want to point at
        std::cout << "aFunction() is called\n";
    }
};

template<class T>
class B {
public:
    void setFunction( void (T::*func)() ) {
        p_func = func;
    }
    void (T::*p_func)(); // the function pointer
    void callfunc()
    {
       (t.*p_func)(); //call pointer to member
    }
   private:
   T t; 
};

int main() {
    B<A> obj;
    obj.setFunction(&A::aFunction);
    return 0;
}

Live Example

【讨论】:

  • 我尝试了您的第一个解决方案(正如我在问题中所述)。这意味着我需要另一个 template &lt;class Class&gt; 在成员变量声明之前,根据编译器这是非法的。我会试试boost::bind-方法。
  • 我也这么认为,但是按钮需要有几个功能指针:悬停时、停止悬停时、单击时和释放时。我不能让他们都指向同一个班级。但我会在一分钟后回来,现在我正在尝试先安装 boost 库:) 已经感谢您的快速回答!
  • 好的,我玩了一下你给我的函数,但这些似乎与我使用的通常指针没有太大不同。由于您仍然需要template &lt;class Class&gt; 语法,我每个班级不能使用超过一次...
【解决方案2】:

我自己找到了完整的答案,同时寻找一种方法来保存 * 未知类型的对象,而不使用模板或 void 指针,已回答 here。解决方案有点狡猾,因为您必须创建一个允许某些转换的虚拟父级。

这个想法是您创建一个 Parent 并且允许指向的每个对象都必须从它继承。通过这种方式,您可以创建一个指针为Parent *obj,它可以包含多种类型的对象,但当然只能包含从Parent 继承的类。

这同样适用于函数指针。如果您将指针定义为void (Parent::*func)() 作为成员变量。你可以向用户询问一个模板函数指针template &lt;class Class&gt; setFunction( void (Class::*f)() ),它可以保存任何指向任何类的指针。现在您需要将函数指针转换为所需的类Parent:static_cast&lt;void(Parent::*)()&gt;(f)。请注意,这仅在 Class 从 Parent 继承时才有效。否则会出现编译错误。

最小的工作示例

#include <iostream>
using namespace std;

// dummy class Parent
class Parent {};

// class A
class A : public Parent { // Mind the inheritance!
public:
    A(int n) : num(n) {}

    void print() {  // <- function we want to point to
        cout << "Number: " << num << endl;
    }

    int num;
}

// class B, will hold the 2 pointers
class B {
public:
    B() {}

    template <class Class>  // will save the function and object pointer
    void setFunction( void (Class::*func)(), Class *obj) {
        function = static_cast<void(Parent::*)()>(func);
        object = obj;
    }

    void execFunction() {  // executes the function on the object
        (object->*function)();
    }

    void (Parent::*function)(); // the function pointer
    Parent *object;             // the object pointer
}

int main() {
    A a(5);
    B b;

    b.setFunction(&A::print, &a);
    b.execFunction();

    return 0;
}

我不太喜欢这个解决方案。更好的解决方案是 B 类可以有一个函数,当需要执行该函数时它返回一个布尔值。这样您就可以简单地将if 语句放在执行所需函数的main 函数中。

A a(5);
B b;
while (;;) {
    if (b.aTest())
        a.print();
}

B::aTest() 声明为

bool B::aTest();

希望这可以帮助遇到同样问题的任何人。所以这是完全可能的,但在我看来非常狡猾,我不鼓励人们使用第一种方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-27
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    相关资源
    最近更新 更多