Cpp 语言中用什么回调方法最佳

Posted on Sun 07 January 2024 in Journal

Abstract Cpp 语言中用什么回调方法最佳
Authors Walter Fan
 Category    learning note  
Status v1.0
Updated 2024-01-07
License CC-BY-NC-ND 4.0

C/C++ 语言中用什么回调方法最佳

在 C++ 中,最为熟悉的回调方法莫过于观察者模式

#include <iostream>
#include <vector>

// Observer interface
class Observer {
public:
    virtual void update(int value) = 0;
};

// Concrete Observer
class ConcreteObserver : public Observer {
public:
    void update(int value) override {
        std::cout << "ConcreteObserver received update with value: " << value << std::endl;
    }
};

// Subject interface
class Subject {
public:
    virtual void addObserver(Observer* observer) = 0;
    virtual void removeObserver(Observer* observer) = 0;
    virtual void notifyObservers(int value) = 0;
};

// Concrete Subject
class ConcreteSubject : public Subject {
private:
    std::vector<Observer*> observers;

public:
    void addObserver(Observer* observer) override {
        observers.push_back(observer);
    }

    void removeObserver(Observer* observer) override {
        auto it = std::remove(observers.begin(), observers.end(), observer);
        observers.erase(it, observers.end());
    }

    void notifyObservers(int value) override {
        for (Observer* observer : observers) {
            observer->update(value);
        }
    }
};

int main() {
    // Create ConcreteSubject and ConcreteObserver instances
    ConcreteSubject subject;
    ConcreteObserver observer1;
    ConcreteObserver observer2;

    // Add observers to the subject
    subject.addObserver(&observer1);
    subject.addObserver(&observer2);

    // Notify observers of a state change
    subject.notifyObservers(42);

    // Remove one observer
    subject.removeObserver(&observer1);

    // Notify remaining observer of another state change
    subject.notifyObservers(99);

    return 0;
}

在实际的编程实践中,这样做挺啰嗦,自从 C++ 有了 std::bind, std::function 以及 lambda, 代码可以更简单

#include <iostream>
#include <functional>

class MyClass {
public:
    // Member function that will be used as a callback
    void memberFunctionCallback(int value) {
        std::cout << "Member Function Callback invoked with value: " << value << std::endl;
    }
};

int main() {
    // Create an instance of the class
    MyClass myInstance;

    // Define a std::function for the callback using std::bind
    std::function<void(int)> memberFunctionCallback = std::bind(&MyClass::memberFunctionCallback, &myInstance, std::placeholders::_1);

    // Use the registered member function callback
    memberFunctionCallback(42);

    return 0;
}

又如

#include <iostream>
#include <functional>

class CallbackHandler {
public:
    void memberFunctionCallback(int value) {
        std::cout << "CallbackHandler's member function invoked with value: " << value << std::endl;
    }
};

class AnotherClass {
public:
    // Function that takes a lambda as a callback
    void registerAndInvokeCallback(std::function<void(int)> callback) {
        // Some other logic...

        // Invoke the callback with a value
        callback(42);
    }
};

int main() {
    CallbackHandler callbackHandler;

    // Register a member function as a lambda
    auto memberFunctionLambda = [&callbackHandler](int value) {
        callbackHandler.memberFunctionCallback(value);
    };

    AnotherClass anotherClass;

    // Use the lambda as a callback in another class
    anotherClass.registerAndInvokeCallback(memberFunctionLambda);

    return 0;
}

在 C 语言中基于 signal 信号的回调也挺好用的, 例如:

#include <glib.h>

// Define a custom object type
#define MY_TYPE_OBJECT (my_object_get_type())
G_DECLARE_FINAL_TYPE(MyObject, my_object, MY, OBJECT, GObject)

struct _MyObject {
    GObject parent_instance;
};

G_DEFINE_TYPE(MyObject, my_object, G_TYPE_OBJECT)

// Define a signal for the custom object
enum {
    SIGNAL_MY_SIGNAL,
    LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

// Callback function for the signal
static void my_signal_callback(MyObject* obj, int value, gpointer user_data) {
    g_print("Signal received with value: %d\n", value);
}

// Function to perform the operation and emit the signal
static void perform_operation(MyObject* obj, int value) {
    // Perform some operation...

    // Emit the signal
    g_signal_emit(obj, signals[SIGNAL_MY_SIGNAL], 0, value);
}

// Class initialization function
static void my_object_class_init(MyObjectClass* klass) {
    signals[SIGNAL_MY_SIGNAL] = g_signal_new("my-signal",
                                             G_TYPE_FROM_CLASS(klass),
                                             G_SIGNAL_RUN_LAST,
                                             0,
                                             NULL, NULL,
                                             g_cclosure_marshal_VOID__INT,
                                             G_TYPE_NONE,
                                             1,
                                             G_TYPE_INT);
}

// Object initialization function
static void my_object_init(MyObject* obj) {
    // Initialization code here...
}

int main() {
    // Initialize GLib
    g_type_init();

    // Create an instance of MyObject
    MyObject* obj = g_object_new(MY_TYPE_OBJECT, NULL);

    // Connect the signal to the callback function
    g_signal_connect(obj, "my-signal", G_CALLBACK(my_signal_callback), NULL);

    // Perform the operation, which will trigger the signal
    perform_operation(obj, 42);

    // Clean up
    g_object_unref(obj);

    return 0;
}

notes

横在我们面前许多事都使人痛苦,可是却不用悲观。骤然而来的风雨,说不定会把许多人的高尚理想,卷扫摧残,弄得无踪无迹。然而一个人对于人类前途的热忱,和工作的虔敬态度,是应当永远存在,且必然能给后来者以极大鼓励的 -- 沈从文


本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。