【问题标题】:Why should I use the static method for using this callback?为什么我应该使用静态方法来使用这个回调?
【发布时间】:2014-03-29 04:12:05
【问题描述】:

我正在尝试实现 Marmalade 的 IwBilling (c++),但我得到的只是错误:“必须调用对非静态成员函数的引用”。 我使用以下代码:

=== [ main cpp file ] ===
#include <s3e.h>
#include "MyGame.h"
int main () {
    IwGxInit();
    {
        MyGame game = new MyGame();
    }
    IwGxTerminate();
}


=== [ MyGame.h ] ===
#include "IwBilling.h"

class MyGame{

    void billingError( void* caller, IwBilling::CIwBillingErrorData* data ) {}

    MyGame() {
        if ( IwBilling::isAvailable() && IwBilling::Init() ) {
            IwBilling::setErrorCallback( billingError ); // !!! ERROR: Reference to non-static member function must be called
        }
    }

};

这里有什么问题?为什么会这样?如果我写:“static void billingError”一切正常。但我不知道在 void billingError 之前使用 static 是否正确?

我不明白为什么我的 MyGame() 构造函数是静态方法?我怎样才能做到非静态?

【问题讨论】:

  • setErrorCallback 的声明在哪里?
  • 它在 IwBilling 类中。这不是我的课,所以我不能改变它。这是一个名为 Marmalade 的 SDK。

标签: c++ constructor static


【解决方案1】:

在 C++ 中,非静态成员函数总是与声明它们的类的实例相关联。因此,为了调用它们,您必须拥有该类的一个实例。因此,如果 billingError() 被声明为非静态的,则必须使用 MyGame 的实例来调用它,如下所示:

MyGame* myGame = new MyGame();
myGame->billingError(); // myGame is the instance for this call

可以在没有类实例的情况下调用静态函数,如下所示:

MyGame::billingError(); // assuming billingError() was declared static

这种区别的原因是非静态成员函数有一个隐含的'this'指针传递给它们,它是一个指向调用该函数的实例的指针(第一个示例中的myGame是内部的'this'指针该功能)。 'this' 指针作为不可见参数传递给函数。另一方面,静态函数没有任何额外的隐式参数。

因为这两种类型的函数有不同的调用约定,指向它们的指针被区别对待。因此,如果您想使用非静态 billingError() 函数,则必须声明 setErrorCallback() 以获取非静态函数指针传递 MyGame 的实例。例如:

class IwBilling {
  void setErrorCallback( void (MyGame::*callback) (void* caller, IwBilling::CIwBillingErrorData* data), MyGame* instance ) {
    // do some stuff
    instance->callback(caller, data);
  }
}

另一方面,如果您不需要 myGame 的实例,那么您可以将 billingError() 声明为静态,并将 setErrorCallback() 回调参数声明为静态函数指针,如下所示:

class IwBilling {
  void setErrorCallback( void (*callback) (void* caller, IwBilling::CIwBillingErrorData* data) ) {
    // do some stuff
    callback(caller, data);
  }
}

【讨论】:

  • 在发布此消息之前,我并没有意识到果酱是什么。我猜您无法控制 setErrorCallback() 的声明方式,因此您必须使用他们的 API。在这种情况下,您必须按照 John 的指示进行操作,并使用静态转换函数包装非静态调用。
【解决方案2】:

不幸的是,IwBilling 回调不遵循传递用户定义的 void* 的通常模式,您可以使用它来指示要调用方法的类的哪个实例。所以你可能会被一些像这样的静态丑陋所困扰:

class MyGame{

    static MyGame* instance; // define and initialize this in your .cpp file

    void billingError( void* caller, IwBilling::CIwBillingErrorData* data ) {}
    static void billingErrorStatic( void* caller, IwBilling::CIwBillingErrorData* data ) {
        instance->billingError(caller, data); // call the non-static method
    }

    MyGame() {
        if ( IwBilling::isAvailable() && IwBilling::Init() ) {
            IwBilling::setErrorCallback( &MyGame::billingErrorStatic );
        }
    }
};

【讨论】:

  • 糟糕,我什至无法编译它。我得到:“Apple Mach-O Linker(Id) 错误:(null):“MyGame::instance”,引用自:”
  • 如何设置“instance”变量?我试图设置“实例=这个;”在 MyGame() 构造函数中,它失败了。如何正确执行?我可以在 MyGame.h 中定义它吗?或者我必须制作 .cpp 并只在那里定义它?
  • 您必须在 .cpp 文件的顶部添加 MyGame* MyGame::instance;,并在构造函数中将其分配给 this
  • 我可以在头文件中声明还是只在 .cpp 中声明?
  • 两者。阅读静态成员变量。
猜你喜欢
  • 2016-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-17
  • 2022-11-24
  • 2011-03-23
  • 1970-01-01
相关资源
最近更新 更多