与其包含的类类型相同的列表

A list with the same type as the class it's contained within

本文关键字:列表 类型 包含      更新时间:2023-10-16

我正在尝试创建一个简单的事件系统,它将有许多不同的事件。因此,我尝试创建一个事件类,它允许您注册函数,获取正确类型的事件,并返回布尔值。

我想要的是,Event的任何子类中的方法post都将采用该子类,而不是Event,并且每个子类中列表listeners中的函数应该采用正确的子类类型。这是我已经拥有的代码,它强制函数转换为正确的事件类型:

事件.h:

namespace events {
    class Event {
        public:
            static const std::List<bool (*)(Event)> listeners;
            void post(Event event);
    }
    class ExampleEvent : Event {
        int eventData;
    }
}

事件.cpp:

namespace events {
    void Event::post(Event event) {
        for(int i = 0; i < listeners.size(); i++) {
            if(listeners[i](event)) return;
        }
    }
}

有没有什么方法可以让它在不必执行以下操作的情况下处理子类事件?

bool handleExample(Event event) {
    ExampleEvent exampleEvent = (ExampleEvent)event;
    std::cout << exampleEvent.eventData << std::endl;
    return false;
}
// Somewhere else in the code
ExampleEvent::listeners.push_back(&handleExample);

我为任何错误的代码道歉,我还没有完全掌握语言规则。

常用的方法是使用CRTP:

namespace events {
    template<typename Derived>
    class Event {
        public:
            static const std::list<bool (*)(Derived)> listeners;
            void post(Derived event)
            {
                 static_cast<Derived&>(*this).post(event);
            }
    };
    class ExampleEvent : Event<ExampleEvent> {
        int eventData;
        void post(ExampleEvent event)
        {
             //implement post
        }
    };
}

只需使用虚拟函数:

namespace events {
    class EventHandler {
        public:
            static const std::list<Event*> listeners;
            void post() {
                for (Event * listener : listeners) {
                   if (listener->post()) break;
                }
            }
    };
    class BaseEvent {
    public:
       virtual bool post() = 0;
       virtual ~BaseEvent() {}
    };
    class ExampleEvent : public BaseEvent { // use public inheritance
        int eventData;
    public:
        virtual bool post() override {
           if (eventData == 0) return true;
           return false;
        }
    };
}