1

I'm trying to create a C++ application using SDL and SDL_Mixer for audio, and am trying to follow this tutorial. However, using SDL_Mixer's Mix_HookMusicFinished() isn't working, giving the error: argument of type 'void (CApp::)()' does not match 'void (*)()'

I've researched this error, and it seems the problem is that cleanMusic is a member function of CApp. I can't tell how to solve the problem, however, since most problems similar to this one are centered around pthread_create(). My cleanMusic() function needs to be able to access music_ which is a private variable of CApp. How can I resolve the error?

Here is the code for CApp.h, CApp::handleKeyEvents(), and CApp::cleanMusic(). Let me know if you need to see something else.

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;
}
genpfault
  • 51,148
  • 11
  • 85
  • 139

2 Answers2

1

Two changes. cleanMusic needs to be static.

static void cleanMusic();

Second, you register the hook with:

Mix_HookMusicFinished(&CApp::cleanMusic);

Since your method is now static, music_ needs to be static as well.

static Mix_Music *music_;

This means that there will only be one instance of this variable shared between all instantiations of CApp. Since I haven't seen all of your code, I can't tell if this is an issue.

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
Erik Nedwidek
  • 6,134
  • 1
  • 25
  • 25
  • That didn't seem to work. Now I'm getting the error: invalid use of member 'CApp::music_' in static member function. – Qazplm123890 May 21 '13 at 00:31
  • Did you also update where the function is defined so that it is void static? It's actually three changes (2 are related). – Erik Nedwidek May 21 '13 at 00:35
  • I just updated the declaration because if I update the definition as well, I additionally get error: cannot declare member function 'static void CApp::cleanMusic()' to have static linkage [-fpermissive]. – Qazplm123890 May 21 '13 at 01:23
  • Sorry, you're quite right. It just goes in the class definition in the .h file. You can't/don't use it in the .cpp file for this purpose. – Erik Nedwidek May 21 '13 at 01:45
  • The reason for the error is that CApp::cleanMusic accesses non-static member music_. – Erik Nedwidek May 21 '13 at 01:51
0

void cleanMusic(); is what is known as a member function. A member function is very different from a normal function. The reason your compiler complains is because Mix_HookMusicFinished expects a normal function pointer of type void (*)(), but you are trying to pass a member function pointer of type void (CApp::*)(). These types are incompatible.

The simplest solution is just to make cleanMusic a normal function and Mix_Music *music; a global:

Mix_Music *music;

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

Another way is to make them both static members:

static void cleanMusic();
static Mix_Music *music_;
Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • Are global variables perfectly acceptable for an application such as a game then? I've read that they should be avoided, but I don't think I can avoid it in this case without breaking the rest of my code. Thank you! – Qazplm123890 May 21 '13 at 00:29
  • @Qazplm123890: Instead of the global, use an anonymous namespace `namespace { Mix_Music *music; }`. This prevents the problems of globals by keeping the name local to the source file. – Jesse Good May 21 '13 at 00:48