简体   繁体   中英

Implementing callback (for C library) as pure virtual in C++ abstract class

I ran into a problem when using a C audio library (PortAudio built with ASIO SDK, but this isn't really relevant to this question; the technical details would only hinder me asking the question) .

Simply put, a certain C function from that library requires me to give it a callback function that returns a certain value and accepts certain parameters; for the sake of clarity, let's say the callback should look like this:

int callback(int arg)

and the call to the library function looks like this:

theCLibraryFuntion(foo, bar, callback);

Using the library like this (ie in the procedural C-style way) works fine, but I would like to wrap the library functionalities that are relevant to me in nicely structured C++ classes. The project I need the library for is the biggest I've worked on so far, so OO-design is a must for me. I want to create an abstract class in C++ that provides a pure virtual function for derived classes to implement, and then have that implementation be used for the callback by a class that knows about the library. In other words, I need actual polymorphism rather than nasty function pointer cruft.

I haven't been able to write such classes so far. The compiler won't allow me to pass nonstatic member functions of any class as callback to the C library function. I understand why, but I would like to know about some workaround for this. As long as that workaround, if it exists, gives me polymorphic behaviour for the front-end classes, I don't care how evil the back-end code becomes. If no such workaround exists, so be it. I understand quite well how C works in the background, but I know little about the technicalities of the OO-features in C++ so I'm going to assume there is a way.

Thanks in advance!

Note: a workaround that would add considerable overhead is likely to be worthless to me. I'm forced to use this C portaudio library because it's the only API that gives me the extremely low latency for audio streaming my project requires, so drastically increasing overhead isn't really an option.

Your code is oversimplified. In real world both the "library function" and the callback will have a void* "user data" parameter. You can pass a pointer to your class instance into "user data" of the "library function" and it will be forwarded into the callback where you can use that pointer to access the object.

class CallbackImplBase {
public:
   virtual void CallbackImpl() = 0;
   static void CallbackToPass( void* userData )
   {
       static_cast<CallbackImplBase*>(userData)->CallbackImpl();           
   }
};

class ActualCallbackImpl : public CallbackImplBase {
     void CallbackImpl() { //implemented here }
};

ActualCallbackImpl callback;
callLibraryFunction( params,
   &CallbackImplBase::CallbackToPass, static_cast<CallbackImplBase*>( &callback ) );

Note the static_cast near the last parameter of the "library function" call. You won't need it unless you have multiple inheritance, it's still there anyway.

As far as I can see, the callbacks in PortAudio, such as this one , take a void* argument for passing user data to them. You can use this to call member functions by passing a class pointer as user data, and writing a small static or non-member function to register as the C-compatible callback. For example:

// C library function
typedef void (*c_library_callback)(void * user_data);
void c_library_start_stuff(c_library_callback, void * user_data);

// C++ class using it
class audio_thing {
public:
    virtual ~audio_thing() {} // Better have one of these in an abstract class

    void start_stuff() {
        c_library_start_stuff(&audio_thing::static_callback, this);
    }
private:
    // C-compatible callback forwards to the implementation
    static void static_callback(void * thing) {
        static_cast<audio_thing*>(thing)->callback();
    }

    // Derived classes implement the callback behaviour
    virtual void callback() = 0;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM