C语言中的强制类型转换(Type Cast)有显式和隐式两种,显式一般就是直接用小括号强制转换,TYPE b = (TYPE)a; 隐式就是直接 float b = 0.5; int a = b; 这样隐式截断(by the way 这样隐式的截断是向 0 取整的,我喜欢这么叫因为 0.9 会变成 0,1.9 变成 1,-0.9 变成 0,-1.9 变成 -1)。
C++对C兼容,所以上述方式的类型转换是可以的,但是有时候会有问题,所以推荐使用C++中的四个强制类型转换的关键字:
- static_cast 静态类型转换。
- reinterpreter_cast 重新解释类型转换。
- dynamic_cast 子类和父类之间的多态类型转换。
- const_cast 去掉const属性转换
**
1)static_cast
**
这应该四种中是最常见的。用法为 static_cast (expression)。
该运算符把 expression 转换为 type-id 类型,但没有运行时类型检查来保证转换的安全性。
主要用法如下:
(1)用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
(2)用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
(3)把空指针转换成目标类型的空指针。
(4)把任何类型的表达式转换成void类型。
所谓的静态,即在编译期内即可决定其类型的转换,用的也是最多的一种。
#include <iostream>
using namespace std;
int main(void)
{
double dPi = 3.1415926;
int num1 = (int)dPi; //c语言的旧式类型转换
int num2 = dPi; //隐式类型转换
// 静态的类型转换:
// 在编译的时 进⾏行基本类型的转换 能替代c⻛风格的类型转换 可以进⾏行⼀一部分检查
int num3 = static_cast<int> (dPi); //c++的新式的类型转换运算符
cout << "num1:" << num1 << " num2:" << num2 << " num3:" << num3 << endl;
return 0;
}
2)reinterpreter_cast
reinterpret_cast 主要有三种强制转换用途:
1、改变指针或引用的类型
2、将指针或引用转换为一个足够长度的整形
3、将整型转换为指针或引用类型。
用法为 reinterpret_cast (expression)。
type-id 必须是一个指针、引用、算术类型、函数针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。
对数据的二进制重新解释,但是不改变其值。
class Animal {
public:
void cry()
{
std::cout << "Animal cry" << std::endl;
}
};
class Book {
public:
void look()
{
std::cout << "Book look " << std::endl;
}
};
int main()
{
Animal* a = new Animal();
a->cry();
Book* b = reinterpret_cast<Book*>(a); //强制类型的转换
b->look();
getchar();
return 0;
}
3)dynamic_cast
用法为 dynamic_cast (expression)。
几个特点如下:
(1)其他三种都是编译时完成的,dynamic_cast 是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换
(3)dynamic_cast 要求 <> 内所描述的目标类型必须为指针或引用。dynamic_cast 转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回 nullptr
(4)在类的转换时,在类层次间进行上行转换(子类指针指向父类指针)时,dynamic_cast 和 static_cast 的效果是一样的。在进行下行转换(父类指针转化为子类指针)时,dynamic_cast 具有类型检查的功能,比 static_cast 更安全。 向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。Dynamic_cast操作符则可以在运行期对可能产生问题的类型转换进行测试。
(5)使用 dynamic_cast 进行转换的,基类中一定要有虚函数,否则编译不通过(类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义)。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表
class ProductBase
{
public:
virtual ~ProductBase() {};
};
class ProductA :public ProductBase
{
};
int main()
{
ProductA * proA = new ProductA();
ProductBase * base = dynamic_cast<ProductBase *>(proA);
ProductA *proA1 = dynamic_cast<ProductA*>(base);//向下转换,基类没有虚函数编不过
getchar();
return 0;
}
4)const_cast
const_cast<目标类型>(标识符):目标类型只能是指针或者引用
const_cast与之前介绍的各种转换都不同,它只是负责给变量增加或者删除一些属性,以保证编译器可以编过;
class Test {
public:
int data;
};
int main()
{
const Test a = { 200 };
//Test a1 = const_cast<Test>(a); //错误,const_cast 目标类型只能是引用或者指针
//a1.data = 100;
Test& a2 = const_cast<Test&>(a);
a2.data = 100;
std::cout << a.data << ' ' << a2.data << std::endl;
Test* a3 = const_cast<Test*>(&a);
a3->data = 100;
std::cout << a.data << ' ' << a3->data << std::endl;
const int x = 3;
int& x1 = const_cast<int&>(x);
x1 = 200;
std::cout << x << ' ' << x1 << std::endl;
int* x2 = const_cast<int*>(&x);
*x2 = 300;
std::cout << x << ' ' << *x2 << std::endl;
getchar();
return 0;
}