当前位置: 首页 > news >正文

C++ 中dynamic_cast使用详解和实战示例

0.核心结论

dynamic_cast运行时类型识别(RTTI) 的主要工具,用于在 继承体系中安全 的类型转换。
只有两种情况应该使用它:

  1. 基类指针 / 引用 → 派生类指针 / 引用(runtime 检查)
  2. 多态继承体系中做跨层转换

如果没有虚函数表(没有 virtual 函数),就不能用


1. dynamic_cast 什么时候能用?

必须满足:

  • 必须是 类类型
  • 必须处于 继承体系
  • 父类必须至少有一个 虚函数(一般是 virtual destructor)

示例:

struct Base {virtual ~Base() {}
};struct Derived : Base {};

只有这样 dynamic_cast 才能工作。


2. dynamic_cast 四种合法用法

2.1 基类指针 → 派生类指针(最常用)

Base* b = new Derived;
Derived* d = dynamic_cast<Derived*>(b);
if (d) { /* 成功 */ }
  • 成功:返回有效指针
  • 失败:返回 nullptr(非常安全!)

SLAM 框架里常用于模块的统一接口管理,例如:

Frontend* f = factory();
Tracking* t = dynamic_cast<Tracking*>(f);

2.2 基类引用 → 派生类引用(不安全,会抛异常)

Base& b = someRef;
try {Derived& d = dynamic_cast<Derived&>(b);
} catch (std::bad_cast& e) {// 转换失败
}

失败则抛 std::bad_cast

一般不建议在性能敏感代码使用引用形式的 dynamic_cast。


2.3 多重继承下横向转换

struct A { virtual ~A() {} };
struct B { virtual ~B() {} };
struct C : public A, public B {};A* a = new C;
B* b = dynamic_cast<B*>(a);   // 允许!

用于一些复杂的组件接口系统。


2.4 void 转为任意类型(但要有类型信息)*

void* p = some_base_ptr; 
Base* b = dynamic_cast<Base*>(p); // 不行// 必须先为 Base* 才能 cast

严格来说 void* 不能直接 dynamic_cast,必须从多态指针转换而来
通常用于 C 接口和 C++ 之间的桥接。


3. 和 static_cast 的核心区别

要点dynamic_caststatic_cast
安全性运行时检查不检查,容易出错
性能慢,需要 RTTI
失败行为返回 nullptr/抛异常UB(未定义行为)
使用场景不确定真实类型时你能 100% 确定类型时

举例:
SLAM 中模块:Module* m 指向 Tracking*Mapping*LoopClosure* 等多种类型
你不能用 static_cast —— 工程大了就会出 bug。


4. 工程实战中常见正确使用方式

4.1 统一模块基类 → 多个子模块之间的识别

Module* mod = manager.getModule("mapping");
Mapping* m = dynamic_cast<Mapping*>(mod);
if (m) m->optimize();

用于组件化架构(类似 ORB-SLAM / 自研框架)。


4.2 事件总线 / 消息总线中识别消息类型

Message* msg = receiver.pop();if (auto* imu = dynamic_cast<IMUMessage*>(msg)) { ... }
else if (auto* lidar = dynamic_cast<LidarMessage*>(msg)) { ... }

比硬编码 type 字段更安全。


4.3 后端优化节点类型识别

例如继承自 Factor 的不同残差项:

Factor* f = graph.getFactor(i);
if (auto* imu = dynamic_cast<IMUFactor*>(f)) { ... }
if (auto* pose = dynamic_cast<PoseFactor*>(f)) { ... }

4.4 点云处理管线中识别不同 Frame 类型

FrameBase* f = loader.load("cloud.bin");if (auto* kf = dynamic_cast<KeyFrame*>(f)) { ... }
else if (auto* lf = dynamic_cast<LocalFrame*>(f)) { ... }

5. 性能问题(非常关键)

dynamic_cast 会:

  • 检查指针真实类型(RTTI)
  • 多态继承下可能遍历 vtable
  • 多重继承下可能跳指针偏移

不是零成本操作。
在 SLAM / 优化环节中大量调用会造成性能下降。

常规 SLAM 工程做法:

每次都 dynamic_cast

不好。

** 用枚举 + 虚函数替代大部分 dynamic_cast**

例如:

enum class FrameType { KeyFrame, LocalFrame };struct FrameBase {virtual FrameType type() const = 0;
};

但:当继承非常复杂时,dynamic_cast 最终还是跑不掉。


6. 工程实践要点

给基类加虚析构

struct Base { virtual ~Base() = default; };

尽量避免多重继承

(尤其不能设计出钻石继承)

不要在高频循环中使用 dynamic_cast

(如 SLAM tracking 循环)

用 dynamic_cast 做一次类型识别,之后缓存结果

(常用技巧)

if (auto* m = dynamic_cast<Mapping*>(mod)) {mapping_module = m;  // 缓存
}

不要把业务逻辑写到 type 判断上

多态设计 + 虚函数 经常比 RTTI 好。


7. 常见错误

对没有 virtual 的类使用

struct A {};
struct B : A {};
A* a = new B;
dynamic_cast<B*>(a); // UB

用 static_cast 代替 dynamic_cast

容易踩雷。

在模板/泛型代码中滥用 dynamic_cast


8. 实用总结

当不确定指针实际指向哪个派生类时,用 dynamic_cast。
当能确定类型时,用 static_cast。
基类必须有虚函数。
失败返回 nullptr。


9.综合示例:SLAM 系统中的模块管理与 dynamic_cast

目标场景

假设一个 SLAM 系统有多种模块:

  • Tracking(前端)
  • Mapping(后端)
  • LoopClosure(回环检测)
  • Viewer(可视化)

用一个 ModuleManager 来管理所有模块,
并通过 dynamic_cast 进行运行时类型识别,
以便在调度任务时执行不同逻辑。


1. 模块基类(必须有 virtual)

class Module {
public:virtual ~Module() = default;virtual std::string name() const = 0;virtual void process() = 0;
};

2. 若干子模块

class Tracking : public Module {
public:std::string name() const override { return "tracking"; }void process() override {// 前端跟踪逻辑}void trackFeatures() { /* 特征跟踪 */ }
};class Mapping : public Module {
public:std::string name() const override { return "mapping"; }void process() override {// 后端优化逻辑}void optimize() { /* 后端优化 */ }
};class LoopClosure : public Module {
public:std::string name() const override { return "loop"; }void process() override {// 回环检测逻辑}void detectLoop() { /* 回环逻辑 */ }
};

3. 模块工厂(按字符串创建对象)

class ModuleFactory {
public:static std::unique_ptr<Module> create(const std::string& type) {if (type == "tracking") return std::make_unique<Tracking>();if (type == "mapping")  return std::make_unique<Mapping>();if (type == "loop")     return std::make_unique<LoopClosure>();return nullptr;}
};

4. 模块管理器

(这里会展示 dynamic_cast 的推荐使用方式)

class ModuleManager {
public:void addModule(std::unique_ptr<Module> mod) {// 缓存 raw 指针用于 quick lookupmodules_[mod->name()] = mod.get();// 缓存 unique_ptr 来管理生命周期owned_.push_back(std::move(mod));}Module* get(const std::string& name) {return modules_.count(name) ? modules_[name] : nullptr;}// 统一调度所有模块void runOnce() {for (auto& kv : modules_) {Module* mod = kv.second;dispatch(mod);}}private:// 这里展示 dynamic_cast 的核心使用方式static void dispatch(Module* mod) {// 1. Trackingif (auto* m = dynamic_cast<Tracking*>(mod)) {m->trackFeatures();return;}// 2. Mappingif (auto* m = dynamic_cast<Mapping*>(mod)) {m->optimize();return;}// 3. Loop closureif (auto* m = dynamic_cast<LoopClosure*>(mod)) {m->detectLoop();return;}// fallback(基类逻辑)mod->process();}private:std::unordered_map<std::string, Module*> modules_;std::vector<std::unique_ptr<Module>>     owned_;
};

5. 使用示例(

int main() {ModuleManager mgr;mgr.addModule(ModuleFactory::create("tracking"));mgr.addModule(ModuleFactory::create("mapping"));mgr.addModule(ModuleFactory::create("loop"));// 执行一帧 SLAM 主循环mgr.runOnce();return 0;
}

http://www.dtcms.com/a/614002.html

相关文章:

  • Git笔记---简单介绍与基本使用
  • php网站开发项目经验如何写wordpress是什么软件
  • 手机网站排名优化软件怎么查网站开发者联系方式
  • 菲律宾有做网站的吗人人开发网站
  • 部署Cloudflare免费图床——免费开源强大
  • Vue Router 3 升级 4:写法、坑点、兼容一次讲透
  • JSP 、JSTL、MVC分层思想——以登录验证为例
  • 新操作系统。
  • Hutool-JSON 工具类超全使用指南:告别 JSON 处理繁琐操作
  • 445 端口(SMB 服务)完整渗透流程总结
  • 咔咔做受视频网站摄影师网站建设
  • 大连建设网网址是多少啊重庆seo网站设计
  • TDengine 字符串函数 POSITION 用户手册
  • 燕郊建设局网站网站排名首页前三位
  • Docker容器使用手册——进阶篇(下)
  • C++入门指南:开启你的编程之旅
  • 智取能量:如何最大化战斗分数?
  • php网站开发技术要点网站模板制作流程
  • 进程和诊断工具速查手册(8.13):VMMap / DebugView / LiveKd / Handle / ListDLLs 一页式现场排障清单
  • 【ros2】ROS2话题(Topic)通信完全指南:订阅与发布详解
  • 网站安全证书有问题如何解决网站地图如何做
  • 演练:使用VB开发多智能体协作的荣格八维分析器
  • 第8章 广播机制
  • 最近的一对
  • 网站设计建网站互联网是做什么的
  • 【C++】AVL树:详细使用及旋转
  • 网站开发技术的雏形 cgi满18点此转入2o2
  • 小华HC32L136K8TA 单片机新建 MDK5 工程模板(二)
  • Qt告警clazy-detaching-temporary浅谈
  • 前端构建工具扩展,Webpack插件开发