将类成员函数作为参数传递

时间:2013-05-12 08:51:36

标签: c++ function pointers

我有一个类如下,主要方法如下:

class Mesh
{
public:
    void draw()

    void draw(){}
}

int main(int argc,char* argv[])
{
    Mesh mesh;
    glutDisplayFunc(mesh.draw);
}

所以我想将对象的成员函数作为参数传递,但编译器显示以下错误消息:

error: argument of type ‘void (Mesh::)()’ does not match ‘void (*)()’

我做错了什么?

2 个答案:

答案 0 :(得分:2)

由于draw是非静态成员函数,因此需要对该类的实例进行操作。

在纯C ++中,您将使用函数对象(a.k.a。“functor”,请参阅std::function或其前身boost::function)。遗憾的是,这不是C或C API中的一个选项。

在这种情况下,由于没有数据传递给回调,你必须制作某种静态函数(静态类或文件静态函数),在调用它时做正确的事。

如果你只有一个Mesh,那么很简单:要么让类中的所有东西都是静态的(在这种情况下它基本上是命名空间),要么有一个非成员函数调用draw针对Mesh的一个实例:

// at some global-ish file scope...

// we define our class
class Mesh { ... };

// and here's the one global instance of it
Mesh myOneMesh;

// and here is our global / static function that "knows"
// which instance to draw
void drawMyOneMesh() { myOneMesh.draw(); }

// then, in the main flow of your program:
glutDisplayFunc( &drawMyOneMesh );

如果您有多个网格,看起来您可以做的最好的事情是将其关闭当前窗口。在不了解您的应用程序或GLUT API的情况下,我可能会做这样的事情来启用每个窗口的网格回调:

#include <map>

// this could also be a class with all-static members, if one
// were so inclined.  might be worth it, if only to protect 'map'
// from external meddling.

namespace WindowToMesh
{

    typedef std::map< int, Mesh * > Map;
    Map map;

    void addMapping( int win, Mesh * mesh )
    {
        map.insert( { win, mesh } );
    }

    void removeMapping( int win )
    {
        map.erase( win );
    }

    void draw()
    {
        int win = glutGetWindow();
        Map::iterator it = map.find( win );
        if ( it != map.end() )
            it.second->draw();
    }

} // end namespace WindowToMesh

现在,在您的主程序中,您可以将新的Mesh与当前窗口相关联:

Mesh * m = new Mesh( ... );
WindowToMesh::addMapping( glutGetWindow(), m );

您可以将(有效静态)WindowToMesh::draw函数关联为回调:

glutDisplayFunc( &WindowToMesh::draw );

当您准备销毁Mesh时,请确保您在同一窗口中,然后:

WindowToMesh::removeMapping( glutGetWindow() );

根据其他因素,进行双向映射可能是有意义的(因此您可以通过Mesh *而不仅仅通过窗口int查找内容,或者对其进行强力扫描罕见的注销等

我没有可以测试的环境,但它应该很接近。祝你好运!

答案 1 :(得分:1)

问题是成员函数指针需要调用某些信息,即要调用的实例,然后{{1}可以访问指针在成员函数的实现中,因此可以访问成员变量。我想你想这样做,因为你的设计看起来像是要画出this中定义的东西。

有可能将成员函数指针转换为“普通”函数指针。但是你必须记住,一旦调用这个函数,这条信息(Mesh实例)就必须可用。这意味着从成员函数指针到“普通”函数指针的典型转换会添加一个参数(实例)。

Mesh接受glutDisplayFunc()函数指针,即参数列表,因此它不会告诉被调用函数任何。您必须确保一旦调用传递的函数,您就可以重建“上下文”,即void(*)(void)实例。

这可以通过从代码中的全局点指向Mesh实例来完成。当您调用我们即将编写的辅助函数时,将始终使用它。因此,当您将指针传递给Mesh时,我们的帮助函数知道要使用哪个glutDisplayFunc(),一旦我们告诉它应该使用它。

Mesh

此解决方案有限制。您不能在不同的实例中重用相同的函数指针。因此,您无法将任何实例转换为函数指针,但每个全局定义的实例指针只能转换一个。但是,由于您只想将绘制函数传递给class Mesh { public: void draw() { ... } } Mesh *instance; // Helper function called by glut: void display() { // Now we can access a particular instance: instance->draw(); } int main(int argc,char* argv[]) { Mesh mesh; // First point to this instance globally: instance = &mesh; // Then, pass our helper function which now has an empty parameter list: glutDisplayFunc(&display); } ,因此您只需要执行一次,因此它应该没问题。我只是不想让你保持这种“危险”。 ;)