Regular cast vs. static_cast vs. dynamic_cast

Regular cast vs. static_cast vs. dynamic_cast

技术背景

在 C++ 编程中,类型转换是一项常见的操作。不同的类型转换方式适用于不同的场景,理解它们的区别和使用方法对于编写安全、高效的代码至关重要。C++ 提供了多种类型转换运算符,包括 static_castdynamic_castconst_castreinterpret_cast 以及传统的 C 风格类型转换(Regular cast)。

实现步骤

static_cast

static_cast 主要用于基本数据类型之间的转换,以及相关类型指针或引用之间的转换。它不进行运行时检查,适用于你明确知道类型转换是安全的情况。

1
2
3
4
5
6
7
8
9
10
11
void func(void *data) {
// Conversion from MyClass* -> void* is implicit
MyClass *c = static_cast<MyClass*>(data);
// ...
}

int main() {
MyClass c;
// func(&c) will be called
start_thread(&func, &c).join();
}
CPP

dynamic_cast

dynamic_cast 用于在继承层次结构中进行安全的类型转换,特别是在不知道对象的动态类型时。它会在运行时进行类型检查,如果转换失败,对于指针类型会返回 nullptr,对于引用类型会抛出 bad_cast 异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MyBase {
public:
virtual void test() {}
};
class MyChild : public MyBase {};

int main() {
MyChild *child = new MyChild();
MyBase *base = dynamic_cast<MyBase*>(child); // ok

MyBase *base2 = new MyBase();
MyChild *child2 = dynamic_cast<MyChild*>(base2);
if (child2 == nullptr) {
std::cout << "Null pointer returned";
}

try {
MyChild &childRef = dynamic_cast<MyChild&>(*base2);
} catch (std::bad_cast &e) {
std::cout << e.what(); // bad dynamic_cast
}
}
CPP

Regular cast(C 风格类型转换)

C 风格类型转换是一种通用的类型转换方式,它会尝试一系列 C++ 类型转换,并采用第一个成功的转换方式,但不会考虑 dynamic_cast。这种转换方式功能强大,但不够安全,因为它不进行严格的类型检查。

1
2
char c = 10;
int *p = (int*)&c; // C 风格类型转换
CPP

reinterpret_cast

reinterpret_cast 用于处理不相关类型之间的转换,如将一个指针类型转换为另一个不兼容的指针类型。它只是简单地进行二进制数据的复制,不改变底层的位模式。这种转换的结果是系统特定的,不具有可移植性,应谨慎使用。

1
2
char c = 10;
int *r = reinterpret_cast<int*>(&c); // 强制转换
CPP

const_cast

const_cast 主要用于添加或移除变量的 const 修饰符。

1
2
const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // 移除 const
CPP

核心代码

static_cast 示例

1
2
char c = 10;
int *q = static_cast<int*>(&c); // 编译时错误
CPP

dynamic_cast 示例

1
2
3
4
5
6
7
8
9
10
11
12
class MyBase {
public:
virtual void test() {}
};
class MyChild : public MyBase {};

int main() {
MyChild *child = new MyChild();
MyBase *base = dynamic_cast<MyBase*>(child); // 成功
MyBase *base2 = new MyBase();
MyChild *child2 = dynamic_cast<MyChild*>(base2); // 失败,返回 nullptr
}
CPP

Regular cast 示例

1
2
char c = 10;
int *p = (int*)&c; // C 风格类型转换
CPP

reinterpret_cast 示例

1
2
char c = 10;
int *r = reinterpret_cast<int*>(&c); // 强制转换
CPP

const_cast 示例

1
2
const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // 移除 const
CPP

最佳实践

  • 尽量避免使用 C 风格类型转换,因为它不够安全,难以进行代码审查和维护。
  • 当你明确知道类型转换是安全的,并且不需要运行时检查时,使用 static_cast
  • 在继承层次结构中进行类型转换,并且需要运行时检查时,使用 dynamic_cast
  • 仅在必要时使用 reinterpret_cast,因为它的结果是系统特定的,不具有可移植性。
  • 使用 const_cast 时要谨慎,避免修改常量对象的值,以免导致运行时错误。

常见问题

使用 static_cast 进行不兼容类型转换

static_cast 会在编译时进行类型检查,如果进行不兼容类型的转换,可能会导致编译错误。例如,将一个 char 指针转换为 int 指针,会使指针指向的内存大小不匹配,可能导致运行时错误。

1
2
char c = 10;
int *q = static_cast<int*>(&c); // 编译时错误
CPP

dynamic_cast 用于非多态类型

dynamic_cast 只能用于多态类型(即包含至少一个虚函数的类),如果用于非多态类型,会导致编译错误。

1
2
3
4
5
6
7
struct Base { };
struct Derived : Base { };
int main() {
Derived d;
Base *b = &d;
dynamic_cast<Derived*>(b); // 无效,Base 不是多态类型
}
CPP

修改常量对象的值

使用 const_cast 移除 const 修饰符后修改常量对象的值,可能会导致运行时错误,因为常量对象可能位于只读内存区域。

1
2
3
const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst);
*nonConst = 10; // 潜在的运行时错误
CPP

Regular cast vs. static_cast vs. dynamic_cast
https://119291.xyz/posts/regular-cast-vs-static-cast-vs-dynamic-cast/
作者
ww
发布于
2025年5月22日
许可协议