在 C++ 中,有四种强制类型转换操作符,分别是:

  1. static_cast
  2. dynamic_cast
  3. const_cast
  4. reinterpret_cast

这四种类型转换都属于强制类型转换,值得一提的是其实这四种强制转换都是较为危险的,很容易出现错误,尽量少用

1. static_cast

static_cast 用于在类型之间进行转换时,进行编译时类型检查。

它适用于转换那些在语义上兼容的类型,例如基本数据类型、类之间的转换等。

任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_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
#include <iostream>
//类之间的转换
class Base {
public:
virtual void show() { std::cout << "Base" << std::endl; }
};

class Derived : public Base {
public:
void show() override { std::cout << "Derived" << std::endl; }
};

int main() {
Base* b = new Derived();

// 将 Base* 转换为 Derived*,这里是安全的
Derived* d = static_cast<Derived*>(b); // 上行是通过 static_cast
d->show(); // 输出 "Derived"

int x = 10;
double y = static_cast<double>(x); // 基本数据类型转换
std::cout << "y = " << y << std::endl; // 输出 10.0

return 0;
}
  • static_cast 会进行类型检查,并且不允许不兼容的类型之间的转换。

示例:

1
2
3
4
5
6
7
//进行强制类型转换以便执行浮点数除法
int i,j;
double slope=static_cast<double>(j)/i;
//进行指针的转换
void *p=&i;//任何非常量的对象的地址都能存入void*
int *ij=static_cast<int*>(p);

2. dynamic_cast

dynamic_cast 主要用于处理类层次结构中的指针或引用转换。它用于在类之间进行转换时,确保类型安全。dynamic_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
#include <iostream>
#include <typeinfo>

class Base {
public:
virtual void show() { std::cout << "Base" << std::endl; }
};

class Derived : public Base {
public:
void show() override { std::cout << "Derived" << std::endl; }
};

int main() {
Base* b = new Base();
Derived* d = dynamic_cast<Derived*>(b); // 错误的转换,d会为 nullptr
if (d) {
d->show();
} else {
std::cout << "Conversion failed!" << std::endl; // 输出 Conversion failed!
}

delete b;
return 0;
}
  • dynamic_cast 在运行时检查类型,如果转换失败,返回 nullptr(对于指针)或抛出 std::bad_cast 异常(对于引用)。它主要用于确保在继承关系中指针或引用的类型转换安全。

3. const_cast

const_cast 用于修改对象的常量性。

它允许去除或添加 const 限定符。注意,此处只能修改底层const

常见的用途包括将 const 类型的指针或引用转换为非 const 类型,或者反之。

用法:

  • 去除 const 限定符:可以将 const 类型的指针或引用转换为非 const 类型。
  • 添加 const 限定符:可以将非 const 类型的指针或引用转换为 const 类型。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

void modify(const int* ptr) {
// 去除 const 限定符,允许修改对象
int* modifiablePtr = const_cast<int*>(ptr);
*modifiablePtr = 20; // 修改原对象
}

int main() {
const int x = 10;
const int* ptr = &x;

// 去除 const 限定符
modify(ptr); // 此处会导致未定义行为

std::cout << "Modified value: " << x << std::endl; // 未定义行为,x值不可预测
return 0;
}
  • 警告:如果你去除 const 限定符并修改对象,该对象实际上可能是常量,修改它会导致未定义行为,因此这种转换应谨慎使用。

4. reinterpret_cast

reinterpret_cast 是最强大的类型转换操作符,它允许将一种类型的指针或引用转换为另一种完全不相关类型的指针或引用。它不进行任何类型检查,因此使用时必须非常小心。

用法:

  • 主要用于进行指针或引用之间的转换,即使它们在类型上没有任何继承关系。
  • 可以将指针转换为整数类型,或将整数转换为指针类型。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

int main() {
int x = 42;
int* ptr = &x;

// 将指针转换为整数
uintptr_t int_ptr = reinterpret_cast<uintptr_t>(ptr);
std::cout << "Pointer as integer: " << int_ptr << std::endl;

// 将整数转换回指针
int* new_ptr = reinterpret_cast<int*>(int_ptr);
std::cout << "Dereferenced pointer: " << *new_ptr << std::endl; // 输出 42

return 0;
}
  • reinterpret_cast 可以将指针转换为整数,或将整数转换为指针,甚至可以在没有任何类型关系的类型之间进行转换。使用时需要非常小心,因为它可以绕过编译器的类型检查。

总结:四种类型转换的对比

转换操作符 适用场景 编译时检查 运行时检查 类型安全
static_cast 基本类型转换,类之间的转换,指针之间的转换
dynamic_cast 类之间的安全转换,主要用于多态(继承)
const_cast 修改对象的常量性(去除或添加 const 限定符)
reinterpret_cast 强制转换,指针与整数之间的转换,指针之间的任意转换 低(非常危险)

总结

  • static_cast 用于编译时类型安全转换,适合大多数常规类型转换。
  • dynamic_cast 用于多态类型的安全转换,尤其是指针和引用之间的转换,支持运行时类型检查。
  • const_cast 用于修改 const 限定符(添加或去除 const)。
  • reinterpret_cast 用于底层转换,指针和整数之间的转换,不进行类型检查,需要小心使用。