c++ 通过指针在示例上实现类型的调用函数

e7arh2l6  于 2023-04-13  发布在  其他
关注(0)|答案(2)|浏览(144)

我正在尝试实现订阅者-发布者模式。我的基类Subscriber没有侦听器方法,而是声明了类型Handler。这背后的想法是,派生类将能够有多个处理程序,这些处理程序将实现此类型并可以传递给Publisher。我正在尝试调用Notify方法中的处理程序,但是我得到了一个错误,状态是expression must have pointer-to-member type。我怎么才能把我的函数指针转换为一个成员类型,用我的方法可能吗?

class Subscriber {
public:
    typedef void (*Handler)();
};

struct Subscription {
    Subscriber *instance;
    Subscriber::Handler handler;
};

class Publisher {
protected:
    std::vector<Subscription> subscriptions;

public:
    virtual void AddSubscriber(Subscription subscription) {
        this->subscriptions.push_back(subscription);
    };

    virtual void Notify() {
        for (auto subscription : this->subscriptions) {
            auto i = subscription.instance;
            auto h = subscription.handler;

            (i->*h)();
        }
    };
};

我的目标是做一个可扩展的系统能够做这样的事情

struct KeyboardSubscription : Subscription {
    Event event_type;
    Key listened_key;
}

class GUI : Subscriber {
    void OpenMenu() { ... }; // implementing Subscriber::Handler
    void CloseMenu() { ... }; // implementing Subscriber::Handler too
}

class Keyboard : Publisher {
    void Notify() {
        for (KeyboardSubscription subscription : this->subscriptions) {
            auto i = subscription.instance;
            auto h = subscription.handler;
            
            if (subscription.event_type == this->event_type &&
                subscription.listened_key == this->pressed_key)
                (i->*h)();
        }
    }
}

int main() {
   // init GUI and Keyboard...

   KeyboardSubscription sub1;
   sub1.instance = gui_instance;
   sub1.handler = &GUI::OpenMenu;
   sub1.event_type = Key_Down;
   sub1.listened_key = Enter;

   KeyboardSubscription sub2;
   sub2.instance = gui_instance;
   sub2.handler = &GUI::CloseMenu;
   sub2.event_type = Key_Down;
   sub2.listened_key = Esc;

   keyboard_instance.AddSubscription((Subscription)sub1);
   keyboard_instance.AddSubscription((Subscription)sub2);
}
eqqqjvef

eqqqjvef1#

1.也许你不需要Subscription.like这个

class Subscriber {
public:
  typedef void (*Handler)();
  Handler handler;
};

2.you 只需要在Notify()中调用handle()就可以了。

virtual void Notify() {
  for (auto &subscriber : this->subscribers) {
    subscriber->handler();
  }
};
kh212irz

kh212irz2#

我已经实现了我想要的。我只需要像这样声明一个函数类型:

class Subscriber {
public:
    typedef void (Subscriber::*Handler)();
};

下面是一个完整的例子,它可以在没有任何警告的情况下编译,并按预期工作

#include <iostream>
#include <vector>

class Subscriber {
public:
    typedef void (Subscriber::*Handler)();
};

struct Subscription {
    Subscriber *instance;
    Subscriber::Handler handler;
};

class Publisher {
protected:
    std::vector<Subscription*> subscriptions;

public:
    void AddSubscription(Subscription *subscription) {
        this->subscriptions.push_back(subscription);
    }

    virtual void Notify() {
        for (auto subscription : this->subscriptions) {
            auto i = subscription->instance;
            auto h = subscription->handler;

            (i->*h)();
        }
    }
};

struct KeyboardSubscription : Subscription {
    int event_type;
    int listened_key;
};

class GUI : Subscriber {
public:
    void OpenMenu() { // implementing Subscriber::Handler
        std::cout << "Open menu" << std::endl;
    }
    void CloseMenu() { // implementing Subscriber::Handler too
        std::cout << "Close menu" << std::endl;
    }
};

class Keyboard : Publisher {
private:
    int event_type;
    int pressed_key;

public:
    void AddSubscription(Subscription *subscription) {
        Publisher::AddSubscription(subscription);
    }

    void Notify() {
        for (auto sub : this->subscriptions) {
            KeyboardSubscription* subscription = static_cast<KeyboardSubscription*>(sub);
            
            auto i = subscription->instance;
            auto h = subscription->handler;
            
            if (subscription->event_type == this->event_type &&
                subscription->listened_key == this->pressed_key)
                (i->*h)();
        }
    }

    void Event1() {
        this->event_type = 10;
        this->pressed_key = 1;

        this->Notify();
    }

    void Event2() {
        this->event_type = 20;
        this->pressed_key = 2;

        this->Notify();
    }
};

int main() {
    GUI *gui_instance = new GUI;
    Keyboard *keyboard_instance = new Keyboard;

    KeyboardSubscription *sub1 = new KeyboardSubscription;
    sub1->instance = (Subscriber*)gui_instance;
    sub1->handler = (Subscriber::Handler)(&GUI::OpenMenu);
    sub1->event_type = 10;
    sub1->listened_key = 1;

    KeyboardSubscription *sub2 = new KeyboardSubscription;
    sub2->instance = (Subscriber*)gui_instance;
    sub2->handler = (Subscriber::Handler)(&GUI::CloseMenu);
    sub2->event_type = 20;
    sub2->listened_key = 2;

    keyboard_instance->AddSubscription((Subscription*)sub1);
    keyboard_instance->AddSubscription((Subscription*)sub2);

    keyboard_instance->Event1();
    keyboard_instance->Event2();
}

输出如下:

Open menu
Close menu

相关问题