向上转型(子类→基类指针)隐式安全,无需转换符;向下转型需显式,dynamic_cast要求基类有虚函数以支持rtti,static_cast不检查类型安全性。

向上转型(子类指针 → 基类指针)是隐式且安全的
编译器允许你直接把 Cat* 赋给 Animal*,不需要任何转换操作符。这是因为派生类对象内存布局中,基类子对象总位于起始位置,Animal* 只是“换种方式看同一块内存”。
关键点:
- 无需
static_cast,写Animal* a = new Cat;就合法 - 调用虚函数时,仍走
Cat的虚函数表,多态正常工作 - 基类必须有虚函数(至少虚析构)才能支持后续安全的向下转型
- 即使基类没虚函数,向上转型本身也不报错,但失去运行时类型信息
向下转型(基类指针 → 派生类指针)必须显式且带检查
你不能直接写 Cat* c = new Animal; —— 这是语法错误。但如果你有一个 Animal*,想把它转成 Cat*,就得选对工具:
-
static_cast<cat>(animal_ptr)</cat>:编译通过,但不验证实际类型;若animal_ptr实际指向Animal对象,后续访问Cat特有成员就是未定义行为 -
dynamic_cast<cat>(animal_ptr)</cat>:要求基类有虚函数;运行时查虚函数表,匹配失败返回nullptr;必须判空再用,否则崩溃 - 用
dynamic_cast对引用转型会抛std::bad_cast异常,不是返回空
为什么 dynamic_cast 要求基类有虚函数
因为 dynamic_cast 依赖 RTTI(Run-Time Type Information),而 RTTI 只在含虚函数的类中生成。没有虚函数,对象就没有虚表指针(vptr),也就没有运行时类型标识可查。
常见误操作:
- 基类没声明虚析构,却对它用
dynamic_cast→ 编译失败 - 继承链中某一级用了私有/保护继承 →
dynamic_cast不允许跨这种边界 - 钻石继承且没用 virtual 继承 →
dynamic_cast可能行为不确定
static_cast 向下转型不是“错”,而是“不负责检查”
它适合你知道类型一定匹配的场景,比如工厂函数返回 Base*,但文档保证它总是 Derived*。这时用 static_cast 避免运行时开销。
但要注意:
- 它不会改变对象的
vptr,也不会修正指针偏移(多重继承下可能出问题) - 如果类型不匹配,行为完全不可预测——可能静默错读内存,也可能立即崩溃
- 代码审查时,每个
static_cast向下转型都该有注释说明“此处为何确定安全”
实际中最容易被忽略的一点:向上转型后,哪怕你只存了 Base*,只要原始对象是 Derived 实例、且 Base 有虚函数,dynamic_cast 就能正确还原回去;但如果你用 static_cast 强转一个真正来自 new Base 的指针,它不会报错,却会让后续所有调用都偏离预期。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











