C ++如何通过CallBack方法访问成员变量

时间:2012-08-30 16:16:09

标签: c++ sqlite callback static-methods friend

我正在使用带有静态回调函数的SQLite sqlite3_exec函数来处理一些信息。我想将结果信息打印到一个名为sqlite3_exec的类中定义的文件中。我所说的看起来有点像这样,

class MakingTheCall{

static int CallBack(void *NotUsed, int argc, char **argv, char **azColName)
{
    for(int x = 0; x < argc; x++)
        File << argv[x];
    File<<"\n";
} 

private:
   static ofstream File;
   void call(){
       sqlite3_exec(database, query, callback, 0, &zErrMsg);
   }
};

真的想要的是静态函数使用特定于实例的FILE。因此,MakingTheCall的哪个实例使调用传递了它唯一的非静态FILE对象。

但是因为CallBack是静态的并且必须(我认为)是一个回调,所以它无法访问该类的this指针。所以我的想法是,如果friend函数的函数可以得到this指针。这是假设我正确理解this

我觉得我的思路是有缺陷的。对于函数将使用哪个this,感觉可能仍然存在歧义。

作为本讨论的第2部分,有一个例子可以使用静态友方法吗?它们不是我在第一条评论中阅读here时的互斥修饰语,那么你何时才使用它们?

我是SQLite和CallBacks的新手,所以我可能会错过一些可以让我的生活轻松的东西。像void*指针一样,我该如何使用它?感觉就像是我想要做的事情的关键。

提前致谢。

3 个答案:

答案 0 :(得分:4)

sqlite3_exec()调用中传递对象指针:

sqlite3_exec(database, query, callback, (void*) this, &zErrMsg);

然后你会在回调的NotUsed参数中找回它:

static int CallBack(void *NotUsed, int argc, char **argv, char **azColName)
{
    MakingTheCall* obj = (MakingTheCall*) NotUsed;

    // whatever....
}

严格地说,Callback()函数应该是extern "C"自由函数,而不是静态成员。

答案 1 :(得分:4)

如果使用C++11 - 支持进行编译,则可以使用匿名函数(lambda表达式)。 例如:

class MakingTheCall
{
private:
   ofstream File;
   void call(){
       sqlite3_exec(database, query,
           [&] (void *NotUsed, int argc, char **argv, char **azColName) -> int
           {
               for(int x = 0; x < argc; x++)
               File << argv[x];
               File<<"\n";
           },
           0, &zErrMsg);
   }
};

[&]表示call中可用的所有变量都是通过引用捕获的,包括this - 指针。有关详细信息,请参阅here(wikipedia)

答案 2 :(得分:2)

通常,这是通过在注册回调时将指针作为 closure 参数的一部分传递给对象来实现的。在sqlite3_exec的情况下,API如下:

int sqlite3_exec(
  sqlite3*,                                  /* An open database */
  const char *sql,                           /* SQL to be evaluated */
  int (*callback)(void*,int,char**,char**),  /* Callback function */
  void *,                                    /* 1st argument to callback */
  char **errmsg                              /* Error msg written here */
);

所以我将指针传递给参数4中的对象。你的回调函数仍然是静态的,但它应该做的第一件事是将第一个参数作为指向你感兴趣的对象类的指针。然后,您可以调用所需的函数,该函数允许您写入特定于您已传递的实例的File。所以你的代码可能看起来像这样:

static int CallBack(void *closure, int argc, char **argv, char **azColName)
{
    MakingTheCall* obj = static_cast<MakingTheCall*>(closure);
    obj->WriteToTheFile(argc, argv);
    return 0; // Have to return something.
}

int WriteToTheFile(int argc, char **argv)
{
    for(int x = 0; x < argc; x++)
        File << argv[x];
    File<<"\n";
}