为什么我应该使用静态方法来使用此回调?

时间:2014-03-29 04:12:05

标签: c++ constructor static

我正在尝试实现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()构造函数是静态方法?我怎么能非静态地做呢?

2 个答案:

答案 0 :(得分:2)

在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()static,并将setErrorCallback()回调参数声明为静态函数指针,如下所示:

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

答案 1 :(得分:1)

不幸的是,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 );
        }
    }
};