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

如何获取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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 19:12:20