1. C 语言中的类型转换
在 C 语言中,如果赋值运算符左右两侧的类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值的类型不一致时,就需要发生类型转化。
C 语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。
- 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
- 显式类型转化:需要用户自己处理
C 语言中,意义相近的类型可以完成隐式类型转换。比如 int 和 double,它们都是表示数据大小。 但是指针和整型就不能完成隐式类型转换,但是可以强制转换,因为二者终归是有关联的。但是几乎没有关联的类型就不能转换了。
缺陷: 转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换。
2. C++ 的类型转换
2.1 static_cast
C 语言隐式类型转换:
#include <iostream>
using namespace std;
int main() {
double d = 12.34;
int a = d;
cout << a << endl;
return 0;
}

C++ 的 static_cast:
#include <iostream>
using namespace std;
int main() {
double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;
return 0;
}

static_cast基本对标 C 语言的隐式类型转换。
2.2 reinterpret_cast
指针和整型之间,进行隐式类型转换,会报错:

需要转换为强制类型转换:

C++ 的 reinterpret_cast:
#include <iostream>
using namespace std;
int main() {
int a = 10;
int* p = reinterpret_cast<int*>(a);
cout << p << endl;
return 0;
}

reinterpret_cast基本对标 C 语言的强制类型转换。
2.3 const_cast
const_cast可以把 const 修饰,给去除掉:

为什么 a 和*p 的值不同,但是地址却是相同的?
原因是编译器进行了优化,把 a 直接替换为了常量,或是直接存放在寄存器中。
2.3.1 volatile
volatile:破除掉编译器的优化
#include <iostream>
using namespace std;
int main() {
volatile const int a = 2;
int* p = const_cast<int*>(&a);
*p = 3;
cout << a << endl;
cout << *p << endl;
cout << &a << endl;
cout << p << endl;
return 0;
}

2.3.2 注意
C++ 添加上四种类型转换,主要是为了提高可读性。 比如这里的 const_cast,警醒程序员,这里的转换很危险。 而 C 语言都是一个强制类型转换,就无法区分了。
2.4 dynamic_cast
dynamic_cast,用于将一个父类对象的指针、引用,转换为子类对象的指针或引用 (动态转换)。 向上转型:子类对象指针、引用 --> 父类指针、引用 (不需要转换,赋值兼容规则)。 向下转型:父类对象指针、引用 --> 子类指针、引用 (用 dynamic_cast 转型是安全的)。
注意:
- dynamic_cast 只能用于父类含有虚函数的类
- dynamic_cast 会先检查是否能转换成功,能成功则转换,不能则返回 0
代码:
class A {
public:
virtual void f() {}
int _a = 0;
};
class B : public A {
public:
int _b = 1;
};
问题:

C++ 使用 dynamic_cast 解决问题:

dynamic_cast:在运行时,识别指针是指向父类,还是指向子类
总结:
dynamic_cast 必须用于多态类,父类必须有虚函数。 应对的是向下转换,向上转换有赋值兼容规则,不需要转换
