隐式类型转换就是编译器自动转;
显式类型转换类如
(char)
# 强制类型转换运算符
MSDN 强制转换运算符 (opens new window)
C++ 强制转换运算符| 菜鸟教程 (opens new window)
C 存在隐式转换和显式转换。C++ 的隐式转换和 C 相同,而把 C 的非常笼统且不安全的显式转换细分为了四种显式转换,如下。
# reinterpret_cast
字面意思是按位“重新解释”,可以实现 指针
和另一种指针/整数
的互相转换。
int * int_ptr = new int;
char * char_ptr = reinterpret_cast<char*> int_ptr;
# const_cast
能(且只能)为变量加上或删除 const
、volatile
和 __unaligned
特性。
但需要注意的是,const_cast
修改使用 const
创建的变量是未定义行为。原因是,如果在创建变量时使用 const int
,编译器可以进行优化,修改这种变量是未定义行为(详见 cv 限定符 部分)。
void square(const int* px) {
int* p = const_cast<int*>(px); // const_cast 去掉了 px 的 const volatile 限制
*p = (*p) * (*p);
}
int main() {
int i = 5; // 创建变量时使用 const
const int ci = 5; // 创建变量时使用 const
const int* pi = new int(5); // 创建变量时不使用 const
square(&i);
square(&ci); // 未定义行为
square(pi);
cout << i << " " << ci << " " << *pi;
// 在 g++ 和 msvc 中均输出 25 5 25
// 但 VS 调试器显示 ci 对应内存的值为 25,显然是 cout 语句被编译器优化了
return 0;
}
如果定义为 const volatile
阻止编译器优化,修改这种变量是合法的。
void square(const volatile int* px) {
int* p = const_cast<int*>(px); // const_cast 去掉了 px 的 const volatile 限制
*p = (*p) * (*p);
}
int main() {
int i = 5;
const int ci = 5;
const volatile int cvi = 5; // 使用 volatile 阻止编译器优化
square(&i);
square(&ci); // 未定义行为
square(&cvi);
cout << i << " " << ci << " " << cvi;
// 在 g++ 和 msvc 中均输出 25 5 25
return 0;
}
# static_cast
static_cast<int>
类似于 C 的显式转换,可用于父类向派生类转换、int
向 char
转换等。这些报错都是在编译阶段完成。
float f = 2.33;
int i = static_cast<int>(f); // 合法
struct A {};
struct B: public A {};
int main() {
A a;
B* b = static_cast<B*>(&a); // 合法
return 0;
}
但是不同的是,显式转换是真的什么都可以转,而 static_cast
还是做了一些限制的,比如不能做 const_cast
reinterpret_cast
以及不相关的类型转换。
struct A {};
struct B {};
int main() {
A a;
B* b1 = (B*)&a; // 不报错
B* b2 = static_cast<B*>(&a); // 报错
int i1 = (int)&a; // 不报错
int i2 = static_cast<int>(&a); // 报错
return 0;
}
# dynamic_cast
- 用于多态类型的转换
- 执行行运行时类型检查
- 只适用于指针或引用
- 对不明确的指针的转换将失败(返回
nullptr
),但不引发异常 - 对不明确的引用的转换将抛出
bad_cast
异常
- 可以在整个类层次结构中移动指针,包括向上转换、向下转换
# bad_cast 异常
- 由于强制转换为引用类型失败,dynamic_cast 运算符引发 bad_cast 异常。