目录
将 (type) 作为强制类型转换运算符是 C 语言的做法,C++ 为了保持兼容,也予以了保留。
C++ 引入了四种功能不同的强制类型转换运算符来进行强制类型转换,分别是 static_cast、reinterpret_cast、const_cast 以及 dynamic_cast。
强制类型转换是有一定风险的,有的转换并不一定安全,例如:把整型值转换成指针,把常量指针转换成非常量指针,把基类指针转换成派生类指针等等。C++ 引入新的强制类型转换机制,主要是为了克服 C 语言强制类型转换的以下几个缺点:
没有从形式上体现转换功能和风险的不同。
例如,将 int 强制转换成 double 是没有风险的,而将常量指针转换成非常量指针,将基类指针转换成派生类指针都是高风险的,而且后两者带来的风险不同(即可能引发不同种类的错误),C 语言的强制类型转换形式对这些不同并不加以区分。
将多态基类指针转换成派生类指针时不检查安全性,即无法判断转换后的指针是否确实指向一个派生类对象。
难以在程序中寻找到底什么地方进行了强制类型转换。
static_cast 用于进行比较 "自然"和低风险的转换,例如整型和浮点型、字符型之间的相互转换。
static_cast 不能用于不同类型的指针或引用之间的相互转换,也不能用于整型和指针之间的相互转换。
- #include
- using namespace std;
-
- int main()
- {
- int i = 0;
- double d = 3.14;
- char ch = 'A';
- i = static_cast<int>(d);
- cout << i << endl; // 3
- i = static_cast<int>(ch);
- cout << i << endl; // 65
- return 0;
- }
reinterpret_cast 用于进行不同类型的指针或引用之间的相互转换,以及进行整型和指针之间的相互转换。转换时执行的是逐个比特复制的操作。
这种转换提供了很强的灵活性,但转换的安全性只能由程序员来保证了。例如,程序员执意要将一个 int* 类型的指针转换成 string* 类型的指针也是可以的,但后面使用转换后的指针调用 string 类的成员函数而引发错误,程序员也只能自行承担查找错误的后果。
- #include
- using namespace std;
-
- int main()
- {
- int i = 1;
- char* p = reinterpret_cast<char*>(&i);
- if (*p)
- cout << "小端字节序" << endl;
- else
- cout << "大端字节序" << endl;
-
- int addr = reinterpret_cast<int>(&i);
- cout << hex << addr << endl;
- cout << &i << endl;
- return 0;
- }
const_cast 用于进行去除 const 属性的转换,即可以将 const 指针或引用转换为同类型的非 const 指针或引用。
- int main()
- {
- const int i = 0;
- int* p = const_cast<int*>(&i);
- int& r = const_cast<int&>(i);
- return 0;
- }
reinterpret_cast 可以将多态基类(包含虚函数的基类)的指针强制转换成派生类的指针,但是这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。
dynamic_cast 专门用于将多态基类的指针或引用转换成派生类的指针或引用,而且能够检查转换的安全性,对于不安全的指针转换,转换后返回空指针。
注意:dynamic_cast 是通过 "运行时类型识别(RTTI,Run-Time Type Identification)" 来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换成派生类的指针或引用,这种转换没法保证安全性,只能使用 reinterpret_cast。
- #include
- using namespace std;
-
- // 多态基类
- class Base
- {
- public:
- virtual ~Base() { }
-
- int _i = 0;
- };
-
- // 派生类
- class Derived : public Base
- {
- public:
- int _j = 0;
- };
-
- void func(Base* pb)
- {
- Derived* pd = dynamic_cast
(pb); - if (pd)
- {
- ++pd->_i;
- ++pd->_j;
- cout << pd->_i << " " << pd->_j << endl;
- }
- else
- {
- cout << "转换不安全!!!" << endl;
- }
- }
-
- int main()
- {
- Base b;
- func(&b);
- // 转换不安全!!!
-
- Derived d;
- func(&d);
- // 1 1
- return 0;
- }