C++ 强制类型转换运算符

将类型名作为强制类型转换运算符的做法是 C 语言的老式做法,C++ 为保持兼容而予以保留。

C++ 引入了四种功能不同的强制类型转换运算符以进行强制类型转换:static_castreinterpret_castconst_castdynamic_cast

强制类型转换是有一定风险的,有的转换并不一定安全,如把整型数值转换成指针,把基类指针转换成派生类指针,把一种函数指针转换成另一种函数指针,把常量指针转换成非常量指针等。

C++ 强制类型转换运算符的用法如下:

1
强制类型转换运算符 <要转换到的类型> (待转换的表达式)

例如:

1
double d = static_cast <double> (3*5); //将 3*5 的值转换成实数

一、static_cast

这是最常用的转换,用于“逻辑上相关的类型转换”

  • 特点:
    • 用于基本数据类型转换(如 intdouble
    • 用于类层次结构中,将派生类指针/引用转换为基类指针/引用(向上转型,安全)
    • 将基类指针转换为派生类指针(向下转型,不安全,因为不检查运行时类型)
    • void* 转回具体的指针类型
    • 没有运行时类型检查,如果转换不合理,结果通常是未定义行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

using namespace std;

class A
{
public:
operator int() { return 1; }
operator char*() { return NULL; }
};

int main()
{
A a;
int n;
char* p = "New Dragon Inn";
n = static_cast <int> (3.14); // n 的值变为 3
n = static_cast <int> (a); //调用 a.operator int,n 的值变为 1
p = static_cast <char*> (a); //调用 a.operator char*,p 的值变为 NULL
n = static_cast <int> (p); //编译错误,static_cast不能将指针转换成整型
p = static_cast <char*> (n); //编译错误,static_cast 不能将整型转换成指针
return 0;
}

二、reinterpret_cast

这是“重新解释”位模式的转换,最危险且不可移植reinterpret_cast 用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。转换时,执行的是逐个比特复制的操作。

  • 特点:
    • 它不进行任何值的转换,只是告诉编译器将这块内存空间看作另一种类型
    • 常用于指针与整数之间的转换,或不同指针类型之间的直接强转
    • 极易导致内存错误,除非你非常清楚自己在操作底层位数据,否则应尽可能避免使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>

using namespace std;

class A
{
public:
int i;
int j;
A(int n):i(n),j(n) { }
};

int main()
{
A a(100);
int &r = reinterpret_cast<int&>(a); //强行让 r 引用 a
r = 200; //把 a.i 变成了 200
cout << a.i << "," << a.j << endl; // 输出 200,100
int n = 300;
A *pa = reinterpret_cast<A*> ( & n); //强行让 pa 指向 n
pa->i = 400; // n 变成 400
pa->j = 500; //此条语句不安全,很可能导致程序崩溃
cout << n << endl; // 输出 400
long long la = 0x12345678abcdLL;
pa = reinterpret_cast<A*>(la); //la太长,只取低32位0x5678abcd拷贝给pa
unsigned int u = reinterpret_cast<unsigned int>(pa);//pa逐个比特拷贝到u
cout << hex << u << endl; //输出 5678abcd
typedef void (* PF1) (int);
typedef int (* PF2) (int,char *);
PF1 pf1; PF2 pf2;
pf2 = reinterpret_cast<PF2>(pf1); //两个不同类型的函数指针之间可以互相转换
}

/* output
200, 100
400
5678abed
*/

第 2 行的代码不安全,因为在编译器看来,pa->j 的存放位置就是 n 后面的 4 个字节。 本条语句会向这 4 个字节中写入 500。但这 4 个字节不知道是用来存放什么的,贸然向其中写入可能会导致程序错误甚至崩溃。

上面程序中的各种转换都没有实际意义,只是为了演示 reinteipret_cast 的用法而已。在编写黑客程序、病毒或反病毒程序时,也许会用到这样怪异的转换。

reinterpret_cast 体现了 C++ 语言的设计思想:用户可以做任何操作,但要为自己的行为负责。

三、const_cast

专门用于移除或添加 constvolatile 属性

  • 特点:
    • 它是唯一可以改变对象 const 性质的转换运算符。
    • 注意:移除 const 后,尝试修改原本声明为 const 的原始变量是未定义行为。它通常用于调用第三方库中未标记 const 但实际上不会修改对象的函数。
1
2
3
const string s = "Inception";
string& p = const_cast <string&> (s);
string* ps = const_cast <string*> (&s); // &s 的类型是 const string*

四、dynamic_cast

reinterpret_cast 可以将多态基类(包含虚函数的基类)的指针强制转换为派生类的指针,但是这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。dynamic_cast 专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回 NULL 指针。

dynamic_cast 是通过“运行时类型检查”来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,只好用 reinterpret_cast 来完成。

这是唯一具备运行时类型检查的转换,专门用于多态场景

  • 特点:
    • 要求目标类型必须是“多态类型”(即基类中至少包含一个虚函数)。
    • 如果转换失败(例如向下转型到不正确的派生类):
      • 若是指针转换,返回 nullptr
      • 若是引用转换,抛出 std::bad_cast 异常。
    • 主要用于安全的向下转型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <string>

using namespace std;

class Base
{ //有虚函数,因此是多态基类
public:
virtual ~Base() {}
};

class Derived : public Base { };

int main()
{
Base b;
Derived d;
Derived* pd;
pd = reinterpret_cast <Derived*> (&b);
if (pd == NULL)
//此处pd不会为 NULL。reinterpret_cast不检查安全性,总是进行转换
cout << "unsafe reinterpret_cast" << endl; //不会执行
pd = dynamic_cast <Derived*> (&b);
if (pd == NULL) //结果会是NULL,因为 &b 不指向派生类对象,此转换不安全
cout << "unsafe dynamic_cast1" << endl; //会执行
pd = dynamic_cast <Derived*> (&d); //安全的转换
if (pd == NULL) //此处 pd 不会为 NULL
cout << "unsafe dynamic_cast2" << endl; //不会执行

return 0;
}

/* output:
unsafe dynamic_cast1
*/

C++ 强制类型转换运算符
http://example.com/2026/05/17/C++强制类型转换运算符/
作者
Yu xin
发布于
2026年5月17日
许可协议