static_cast适用于编译器已知安全的转换:数值类型、有继承关系的指针/引用向上转型、explicit构造函数或operator T();向下转型、void*直转、const去除、无继承指针互转等会编译失败。

static_cast 什么时候能用,什么时候会编译失败
它只允许编译器已知的、安全的类型转换,比如数值类型之间(int → double)、有继承关系的指针/引用(向上转型),或者自定义类型中带 explicit 构造函数或 operator T() 的情况。
常见错误现象:error: cannot cast from type 'A*' to type 'B*'(无继承关系的类指针互转)、error: invalid static_cast from type 'void*' to 'int*'(C 风格指针转非 void* 类型,必须先转成中间类型如 char*)。
- 不能绕过 const 正确性:从
const int*→int*会失败,得用const_cast - 不能把
void*直接转成任意具体类型指针,必须经由char*或unsigned char*中转 - 向下转型(基类指针 → 派生类指针)语法上允许,但不安全;运行时行为未定义,除非你 100% 确认对象真实类型
和 C 风格强制转换比,static_cast 多了什么检查
C 风格写法像 (int)3.14 或 (MyClass*)ptr,本质是让编译器“闭嘴照做”,连基本类型兼容性都不拦——比如把 float* 强转成 int* 也能过编译,但很可能引发未定义行为。
static_cast 把这类危险操作直接挡在编译期:
立即学习“C++免费学习笔记(深入)”;
-
static_cast<int>(float_ptr)</int>→ 编译失败(指针类型不相关) -
static_cast<int>(3.14f)</int>→ 允许(数值转换) -
static_cast<char>(void_ptr)</char>→ 允许(void* 是唯一可被 static_cast 接受的源类型)
性能上没差别,都是零开销;区别全在编译期约束力。
什么时候该换 dynamic_cast,而不是硬用 static_cast
当你需要向下转型(基类指针/引用 → 派生类),且不确定实际对象类型时,static_cast 就不该出现——它不会做运行时校验,出错就是崩溃或读垃圾内存。
典型场景:容器里存了一堆 Base*,循环处理时想对其中某几个 DerivedA* 做特殊操作。
- 用
dynamic_cast<deriveda>(base_ptr)</deriveda>,成功返回有效指针,失败返回nullptr(指针)或抛std::bad_cast(引用) - 要求基类至少有一个虚函数(通常是析构函数),否则编译报错:
error: 'Base' is not polymorphic - 有运行时开销(查虚表、type_info 比较),别在 hot path 上反复调用
容易被忽略的隐式转换干扰问题
有时候你以为自己在用 static_cast,其实编译器悄悄插了一步隐式转换,结果行为和预期不符。
例如:static_cast<:string>(42)</:string> 看似想把整数转字符串,但 std::string 没有接受 int 的构造函数,也不会触发 std::to_string —— 这行代码根本编译不过。真正要转字符串,得显式调用 std::to_string(42)。
- 自定义类型间转换必须明确定义转换构造函数或转换运算符,且不能是
explicit(除非你主动加static_cast) - 枚举类(
enum class)到整数必须用static_cast<int>(my_enum)</int>,不能靠隐式转换 - 窄化转换(如
static_cast<char>(256)</char>)在 C++17 后默认是合法的,但值会截断;若开启-Wnarrowing(GCC/Clang),编译器会警告
最麻烦的是混合使用:有人写 static_cast<int>(some_double) + 1</int>,本意是取整再加一,但忘了 static_cast<int></int> 是向零截断,负数时和 std::floor 行为不同——这种细节不看文档就容易翻车。











