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