【问题标题】:C++ function pointers and classesC++ 函数指针和类
【发布时间】:2023-03-31 18:13:01
【问题描述】:

说我有:

void Render(void(*Call)())
{
    D3dDevice->BeginScene();
    Call();
    D3dDevice->EndScene();
    D3dDevice->Present(0,0,0,0);
}

只要我要用来渲染的函数是一个函数或者static成员函数就可以了:

Render(MainMenuRender);
Render(MainMenu::Render);

但是,我真的希望能够使用类方法,因为在大多数情况下,渲染函数会想要访问成员变量,而不是让类实例全局化,例如

Render(MainMenu->Render);

但是我真的不知道该怎么做,仍然允许使用函数和static 成员函数。

【问题讨论】:

    标签: c++ oop class function-pointers


    【解决方案1】:

    您可以创建一个包装函数void Wrap(T *t),它只调用t->Call(),并让Render 将这样的函数与一个对象一起使用。那就是:

    void Wrap(T *t)
    {
      t->Call();
    }
    
    void Render(void (*f)(T *), T *t)
    {
      ...
      f(t);
      ...
    }
    

    【讨论】:

      【解决方案2】:

      有很多方法可以给这只猫换皮,包括模板。我最喜欢的是Boost.function,因为我发现它从长远来看是最灵活的。还请阅读 Boost.bind 以了解绑定到成员函数以及许多其他技巧。

      看起来像这样:

      #include <boost/bind.hpp>
      #include <boost/function.hpp>
      
      void Render(boost::function0<void> Call)
      {
          // as before...
      }
      
      Render(boost::bind(&MainMenu::Render, myMainMenuInstance));
      

      【讨论】:

        【解决方案3】:

        我通过定义一个全局函数“Call”这样做了一次,该函数接受指向您的实例的指针作为成员

        void CallRender(myclass *Instance)
        {
          Instance->Render();
        }
        

        所以渲染变成:

        void Render(void (*Call)(myclass*), myclass* Instance)
        {
          ...
          Call(Instance);
          ...
        }
        

        您的渲染调用是:

        Render(CallRender, &MainMenu);
        

        我知道这很丑,但对我有用(我使用的是 pthreads)

        【讨论】:

          【解决方案4】:

          您不能从指针调用成员函数,除非您也引用了该对象。例如:

          ((object).*(ptrToMember))

          因此,如果不更改渲染方法的签名,您将无法实现这一目标。 This 文章解释了为什么这通常是一个坏主意。

          更好的方法可能是定义一个“渲染器”接口,您的具有渲染方法的类可以实现该接口,并将其作为您的主要渲染方法的参数类型。然后您可以编写一个“StaticCaller”实现来支持通过引用调用您的静态方法。

          例如(我的 C++ 真的很生锈,我也没有编译过这个)。

          
          
          void Render(IRenderer *Renderer)
          {
              D3dDevice->BeginScene();
              Renderer->Render();
              D3dDevice->EndScene();
              D3dDevice->Present(0,0,0,0);
          }
          
          // The "interface"
          public class IRenderer 
          {
          public:
              virtual void Render();
          };
          
          public class StaticCaller: public IRenderer
          {
              void (*Call)();
          public:
          
              StaticCaller((*Call)())
              {
                  this->Call = Call;
              }
          
              void Render()
              {
                  Call();
              }
          };
          
          

          所有这些都是非常样板,但它应该提高可读性。

          【讨论】:

            【解决方案5】:

            【讨论】:

              【解决方案6】:

              您可以使用以下方法声明指向 T 类成员函数的函数指针:

              typedef void (T::*FUNCTIONPOINTERTYPE)(args..)
              FUNCTIONPOINTERTYPE function;
              

              并将其调用为:

              T* t;
              FUNCTIONPOINTERTYPE function;
              (t->*function)(args..);
              

              用可变参数、类型、返回值等将其推断为有用的柯里化系统是单调且烦人的。我听说过关于上述 boost 库的好消息,所以我建议在做任何激烈的事情之前先调查一下。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2018-09-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-09-07
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多