【问题标题】:error: cannot convert 'void (CApp::*)()' to 'void (*)()' for argument '1' to 'void Mix_HookMusicFinished(void (*)())'错误:无法将参数 '1' 的 'void (CApp::*)()' 转换为 'void (*)()' 到 'void Mix_HookMusicFinished(void (*)())'
【发布时间】:2013-05-20 22:59:45
【问题描述】:

我正在尝试使用 SDL 和 SDL_Mixer 为音频创建 C++ 应用程序,并尝试遵循 this 教程。但是,使用 SDL_Mixer 的 Mix_HookMusicFinished() 不起作用,给出错误:'void (CApp::)()' 类型的参数与 'void (*)()' 不匹配

我研究过这个错误,问题似乎是 cleanMusic 是 CApp 的成员函数。然而,我不知道如何解决这个问题,因为大多数与此类似的问题都以 pthread_create() 为中心。我的 cleanMusic() 函数需要能够访问 music_ 这是 CApp 的私有变量。我该如何解决这个错误?

这里是 CApp.h、CApp::handleKeyEvents() 和 CApp::cleanMusic() 的代码。如果您需要看其他内容,请告诉我。

CApp.h

#ifndef CAPP_H
    #define CAPP_H

#include <SDL.h>
#include <SDL_mixer.h>

#include <gl\gl.h>
#include <gl\glu.h>

class CApp {
    private:
        bool isRunning_;
    private:
        void cleanMusic();
    private:
        SDL_Surface *surfDisplay_;
        Mix_Music *music_;
        bool isRotating_;
        GLfloat rQuad_;
    public:
        CApp();
        int run();
    public:
        bool initialize();
        void handleEvents(SDL_Event *event);
        void loopData();
        void render();
        void clean();

    public:
        void handleKeyEvents(SDL_KeyboardEvent *key);
};

#endif // CAPP_H

CApp::handleKeyEvents()

#include "CApp.h"

void CApp::handleKeyEvents(SDL_KeyboardEvent *key) {
    switch(key->keysym.sym) {
        case SDLK_m:
            if (key->state == SDL_PRESSED) {
                if(music_ == NULL) {
                    music_ = Mix_LoadMUS("resources\\audio\\boop.wav");
                    Mix_PlayMusic(music_, 0);
                    Mix_HookMusicFinished(cleanMusic);

                    isRotating_ = true;
                } else {
                    Mix_HaltMusic();
                    cleanMusic();
                    isRotating_ = false;
                }
            }
            break;
        default:
            break;
    }
}

CApp::cleanMusic()

#include "CApp.h"

void CApp::cleanMusic() {
    Mix_FreeMusic(music_);
    music_ = NULL;
}

【问题讨论】:

  • 接受void(*)() 回调的 API 很糟糕。

标签: c++ callback sdl member-function-pointers sdl-mixer


【解决方案1】:

两个变化。 cleanMusic 必须是 static

static void cleanMusic();

其次,你注册钩子:

Mix_HookMusicFinished(&CApp::cleanMusic);

由于您的方法现在是static,所以music_ 也需要是static

static Mix_Music *music_;

这意味着只有一个该变量的实例在 CApp 的所有实例之间共享。由于我没有看到你所有的代码,我无法判断这是否是一个问题。

【讨论】:

  • 这似乎不起作用。现在我收到错误消息:在静态成员函数中无效使用成员 'CApp::music_'。
  • 您是否还更新了函数的定义位置,使其成为 void static?它实际上是三个变化(两个是相关的)。
  • 我刚刚更新了声明,因为如果我也更新定义,我还会收到错误:无法声明成员函数'static void CApp::cleanMusic()' 具有静态链接 [-fpermissive]。
  • 对不起,你说的很对。它只是在 .h 文件中的类定义中。为此,您不能/不要在 .cpp 文件中使用它。
  • 报错原因是CApp::cleanMusic访问非静态成员music_。
【解决方案2】:

void cleanMusic(); 是所谓的成员函数。成员函数与普通函数非常不同。你的编译器抱怨的原因是因为Mix_HookMusicFinished 需要一个void (*)() 类型的普通函数指针,但是你试图传递一个void (CApp::*)() 类型的成员函数指针。这些类型不兼容。

最简单的解决方案就是将cleanMusic 设为普通函数,将Mix_Music *music; 设为全局:

Mix_Music *music;

void cleanMusic() {
    Mix_FreeMusic(music);
    music = NULL;
}

另一种方法是让他们都成为static成员:

static void cleanMusic();
static Mix_Music *music_;

【讨论】:

  • 那么全局变量对于游戏等应用程序是否完全可以接受?我读过应该避免它们,但我认为在这种情况下我不能在不破坏其余代码的情况下避免它。谢谢!
  • @Qazplm123890:使用匿名命名空间 namespace { Mix_Music *music; },而不是全局命名空间。这通过将名称保留在源文件的本地来防止全局变量的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 1970-01-01
相关资源
最近更新 更多