如何获取C++指针指向对象的实际类型?场景问题求解
问题描述
我在结构体中定义了一个可选指针类型的属性event:
struct AnimatedSprite { //...其他属性 Event *event; };
希望存储StartTransitionEvent对象,相关类定义如下:
class Event { public: Event() = default; }; class StartTransitionEvent: public Event { public: int test = 1; };
可以正常创建并赋值:
auto sprite = AnimatedSprite{}; auto newEvent = StartTransitionEvent{}; sprite.event = &newEvent;
但调用如下代码时,不知道如何获取指针的实际类型:
eventBus->EmitEvent<StartTransitionEvent>(sprite->event);
想问:是否需要对event指针做类型检查来获取StartTransitionEvent?或者应该放弃指针,改用std::variant存储所有可能的子类事件?
解决方案
方案一:通过多态类型检查(dynamic_cast)
首先要修正两个基础问题:当前Event不是多态类,无法安全做向下类型转换;另外你代码里的newEvent是局部变量,超出作用域后sprite.event会变成悬空指针,存在内存安全隐患。
第一步,把Event改成多态类,至少添加一个虚析构函数:
class Event { public: Event() = default; virtual ~Event() = default; // 虚析构让类成为多态类型,同时避免内存泄漏 };
之后就可以用dynamic_cast检查并转换类型,只有转换成功时才调用EmitEvent:
if (auto* startEvent = dynamic_cast<StartTransitionEvent*>(sprite->event)) { eventBus->EmitEvent<StartTransitionEvent>(startEvent); } else { // 处理类型不匹配的情况,比如打印日志、抛出异常或直接忽略 }
同时建议用智能指针管理内存,彻底避免悬空指针问题:
#include <memory> struct AnimatedSprite { std::unique_ptr<Event> event; // 用unique_ptr自动管理对象生命周期 }; // 赋值时直接创建动态对象 auto sprite = AnimatedSprite{}; sprite.event = std::make_unique<StartTransitionEvent>();
方案二:改用std::variant存储事件
如果你的事件类型相对固定(或扩展频率很低),std::variant是更安全的选择——它不需要多态,类型检查在编译期完成,还能省去手动内存管理的麻烦。
首先定义包含所有可能事件类型的variant:
#include <variant> // 用std::monostate表示"无事件"的空状态,后续可以添加其他事件类型 using EventVariant = std::variant<std::monostate, StartTransitionEvent, OtherEventType...>; struct AnimatedSprite { EventVariant event; };
赋值时直接存储具体对象:
auto sprite = AnimatedSprite{}; sprite.event = StartTransitionEvent{};
要调用EmitEvent时,可以用std::holds_alternative检查类型,或者用std::visit批量处理所有可能的事件:
// 单独检查某类事件并调用 if (std::holds_alternative<StartTransitionEvent>(sprite.event)) { auto& startEvent = std::get<StartTransitionEvent>(sprite.event); eventBus->EmitEvent<StartTransitionEvent>(&startEvent); } // 用std::visit处理所有事件类型 std::visit([&](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (!std::is_same_v<T, std::monostate>) { eventBus->EmitEvent<T>(&arg); } }, sprite.event);
两种方案的对比
- 多态指针方案:适合事件类型频繁扩展的场景,灵活性高,但需要维护多态结构,运行时类型转换有轻微性能开销。
- std::variant方案:适合事件类型相对固定的场景,编译期类型安全,无需手动管理内存,性能更好,但新增事件类型时需要修改variant的定义。
内容的提问来源于stack exchange,提问作者Oli
相关产品推荐
相关产品推荐

