You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在其他类内部调用接收void*参数的EventManager::AddEventHandler报错问题

问题核心原因

你当前实现的事件管理器仅支持无上下文的普通函数指针,但类的非静态成员函数调用时需要隐含传入类实例的this指针,函数签名和你要求的void(*)(Args...)不匹配,所以无法直接强转为void*传入AddEventHandler。同时你的实现用void*存储函数指针本身存在类型安全问题,传错参数会直接触发内存访问错误。

可行的解决方案

方案1:注册静态成员函数

如果你的回调逻辑不需要访问类的非静态成员,可以直接把类的回调函数声明为static,静态成员函数没有隐含this指针,和普通函数签名一致,可以直接传入:

class MyClass {
public:
    static void OnUpdateCallback(float delta) {
        // 静态函数内仅可访问类静态成员/全局变量
    }
};
// 注册方式
EventManager::AddEventHandler(EventType::OnUpdate, (void*)&MyClass::OnUpdateCallback);

方案2:修改事件管理器支持带上下文的回调(推荐)

这是通用性最强的解决方案,修改你的事件管理器存储回调时同时支持上下文绑定,可以兼容lambda、成员函数、普通函数等所有可调用对象:

#pragma once
#include <vector>
#include <functional>
#include <any>

namespace EventManager {
    enum class EventType {
        OnUpdate,
        OnDraw,
        Size
    };
    // 改用std::function存储回调,天然支持上下文捕获
    extern std::vector<std::function<void(std::any)>> EventCallbacks[(unsigned int)EventType::Size];

    template<typename Func>
    void AddEventHandler(EventType eventId, Func&& callback) {
        EventCallbacks[(unsigned int)eventId].emplace_back([cb = std::forward<Func>(callback)](std::any args) {
            // 根据不同事件类型解析参数,以下为OnUpdate事件示例(参数为float delta)
            if constexpr (std::is_invocable_v<Func, float>) {
                cb(std::any_cast<float>(args));
            }
        });
    }

    template <typename... Args>
    void Trigger(EventType eventId, Args... args) {
        // 单参数事件可直接传参,多参数可以打包为tuple传递
        for (auto& callback : EventCallbacks[(unsigned int)eventId]) {
            if constexpr (sizeof...(Args) == 1) {
                callback((args, ...));
            }
        }
    }
    // RemoveEventHandler和TriggerProcess接口可按同理修改
}

修改后注册类成员函数可以直接用lambda捕获实例指针:

class MyClass {
public:
    void Init() {
        EventManager::AddEventHandler(EventType::OnUpdate, [this](float delta) {
            // 可直接访问类的所有非静态成员
            this->Update(delta);
        });
    }
    void Update(float delta) {
        // 业务逻辑实现
    }
};

方案3:临时适配方案(不推荐)

如果你不想修改现有事件管理器的实现,可以用静态变量存储实例指针,通过静态函数做一层转发:

class MyClass {
public:
    static inline MyClass* s_instance = nullptr;
    static void StaticOnUpdate(float delta) {
        if (s_instance) s_instance->OnUpdate(delta);
    }
    void OnUpdate(float delta) {
        // 业务逻辑实现
    }
};
// 注册时先赋值静态实例指针,再传入静态函数
MyClass::s_instance = this;
EventManager::AddEventHandler(EventType::OnUpdate, (void*)&MyClass::StaticOnUpdate);

该方案仅支持单类实例,线程不安全,仅适合临时测试使用。

内容的提问来源于stack exchange,提问作者P Sawicki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 13:27:00