旧式转型(old-style cast)有两种形式:
- (T)expression //将expression转型为T,C风格的转型动作
- T(expression) //将expression转型为T,函数风格的转型动作
C++ 提供四种新式转型,所以C++不是类型安全的。C++强制类型转换的好处是,能够使程序员更加清晰的明白代码在干什么。
static_cast
可以实现C++中内置基本数据类型之间的相互转换.(只能在有相互联系的类型间进行转换)。用来强迫进行隐式转换,,类型转换在编译期间完成。
- 用于非多态类型的转换
- 不执行运行时类型检查(转换安全性不如 dynamic_cast)
- 通常用于转换数值数据类型(如 float -> int)
- 可以在整个类层次结构中移动指针,子类转化为父类安全(向上转换),父类转化为子类不安全(因为子类可能有不在父类的字段或方法)
向上转换是一种隐式转换。
This is the simplest type of cast which can be used. It is a compile time cast.It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones).
#include <iostream>
using namespace std;
int main()
{
float f = 3.5;
int a = f; // this is how you do in C
int b = static_cast<int>(f);
cout << b;
}
//Output
3
#include <iostream>
using namespace std;
int main()
{
int a = 10;
char c = 'a';
// pass at compile time, may fail at run time
int* q = (int*)&c;
int* p = static_cast<int*>(&c);
return 0;
}
//编译代码时会出错
[Error] invalid static_cast from type 'char*' to type 'int*'
This means that even if you think you can some how typecast a particular object int another but its illegal, static_cast will not allow you to do this.
static_cast转换类object
#include <iostream>
#include <string>
using namespace std;
class Int {
int x;
public:
Int(int x_in = 0)
: x{ x_in }
{
cout << "Conversion Ctor called" << endl;
}
operator string()
{
cout << "Conversion Operator" << endl;
return to_string(x);
}
};
int main()
{
Int obj(3);
string str = obj;
obj = 20;
string str2 = static_cast<string>(obj);
obj = static_cast<Int>(30);
return 0;
}
//Result
Conversion Ctor called
Conversion Operator
Conversion Ctor called
Conversion Operator
Conversion Ctor called
Lets the try to understand the above output:
- When obj is created then constructor is called which in our case is also a Conversion Constructor(For C++14 rules are bit changed).
- When you create str out of obj, compiler will not thrown an error as we have defined the Conversion operator.
- When you make
obj=20
, you are actually calling the conversion constructor.- When you make str2 out of static_cast, it is quite similar to
string str=obj;
, but with a tight type checking.- When you write
obj=static_cast<Int>(30)
, you are converting 30 into Int using static_cast.
static_cast performs a tight type checking, let’s the changed code slightly to see it:
#include <iostream>
using namespace std;
class Base {
};
class Derived : private Base { // Inherited private/protected not public
};
int main()
{
Derived d1;
Base* b1 = (Base*)(&d1); // allowed
Base* b2 = static_cast<Base*>(&d1);
return 0;
}
//会产生Compilation Error
[Error] 'Base' is an inaccessible base of 'Derived'
The above code will not compile even if you inherit as protected. So to use static_cast, inherit it as public.
const_cast
可以使本来不是const类型的数据转换成const类型,或者把const属性去掉,即将对象的常量型转除。是唯一有此能力的C++ Style转型操作符
reinterpret_cast
- 用于位的简单重新解释
- 类似于C的转换,超级无敌,一般不用。滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。
意图执行低级转型,实际动作(及结果)可能取决于编译器,这也就表示它不可移植。例如将一个pointer to int转型为一个int。这一类转型在低级代码以外很少见。
dynamic_cast
主要用来执行“安全向下转型”(safe downcasting),也就是用来决定某对象是否归属继承体系中的某个类型。它是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。
其余三种强制类型转换都是在编译阶段完成,而dynamic_cast是在运行时处理的,运行时要进行类型检查
- dynamic_cast只适用于指针和引用,不能用于内置的基本数据类型的强制转换
- dynamic_cast转换如果成功的话,返回的时指向类的指针或引用,转换失败的话则会返回nullptr,不会引发异常
- dynamic_cast用于多态类型的转换,基类中一定要有虚函数,否则编译不通过,因为只有类中存在虚函数,才会存在让基类指针指向派生类对象的情况,此时这种转换才会有意义。同时,运行中的类型检查需要运行时的类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。
- 在类的转换时,在类层次间进行上行转换时(子类向父类的转换),dynamic_cast和static_cast的效果是一样的,dynamic_cast具有类型检查的功能,比static_cast更安全,可以在整个类层次结构中移动指针,包括向上转换、向下转换。
- 向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。因此不明确的指针的转换将失败。
旧式转型仍然合法,但新式转型较受欢迎。原因:
第一,它们很容易在代码中被辨识出来,因而得以简化“找出类型系统在哪个地点被破坏”的过程
第二,各转型动作的目标愈窄化,编译器愈可能诊断出错误的运用