C++中四种强制类型转换

描述

C++支持四种强制类型转换,所以C++不是类型安全的。分别为:static_cast、dynamic_cast、const_cast、reinterpret_cast。

为什么是用C风格的强制转换可以把想要的任何东西转换成合乎心意的类型,那么为什么还需要一个新的C++类型的强制转换呢?新类型的强制转换可以提供更好的控制强制类型转换的过程,允许控制各种不同种类的强制转换。C++中风格是static_cast(content)。C++风格的强制转换其他的好处是,它们能更清晰的表名它们要干什么,程序员只要看到代码,就能立即知道一个强制转换的目的。

四种转换的区别

可以实现C++内基本数据类型之间的相互转换。

int c = static_cast<int>(3.14);

如果涉及到类的话,static_cast只能在有相互联系的类型中进行相互转换,不一定包含虚函数。

class A {};
class B: public A {};
class C {};

int main() {
	A *a = new A;
	B* b;
	C* c;
	b = static_cast<B>(a);//编译不会报错,B类继承A类
	c = static_cast<B>(a);//编译报错,C类与A类没有任何关系
	return 1;
}

const_cast操作不能在不同种类型之间转换。相反,其仅仅把一个它作用的表达式换成常量。它可以使一个本来不是const类型的数据转化成const类型的;或是把const属性去掉。

const char *p = "hello";
char *q = "world";
p = const_cast<const char *>(q);//直接赋值也是可以的p = q;
q = const_cast<char *>(p);//直接赋值会报错

有着和C风格的强制转换同样的能力。它可以转化任何内置的数据类型为其他任何的数据类型,也可以转化为任何指针类型为其他的类型。它甚至可以转化内置的数据类型为指针,无需考虑类型安全或是常量的情形。

1 其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查,一般在多台类型间进行转换更提倡采用dynamic_cast。

2 不能用于内置的基本数据类型的强制转换。

3 dynamic_cast转换如果成功的话返回的是指向类型的指针或是引用,转换失败则会返回NULL

4 使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不过。之所以要检测虚函数,是因为:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。

5 转换方向分为三种:子类向基类的向上转型(Up cast);基类向子类的向下转型(Down cast);横向转型(Cross cast)。

向上转型是多台的基础,不需要借助任何特殊方法,只需要将子类的指针或是引用付给基类的指针或引用即可,当然dynamic_cast也支持向上转型,而其总是肯定成功的。而对于向下转型和横向转型来说,其实对于dynamic_cast并没有任何区别,它们都属于能力查询。为了方便理解,我们不妨把dynamic_cast视为cross cast:

class Shape {
public:
	virtual ~Shape();
	virtual void draw() const = 0;
};

class Rollable {
public:
	virtual ~Rollable();
	virtual void roll() = 0;
};

class Circle: public Shape, public Rollable {
	void draw() const;
	void roll();
};

class Square: public Shape {
	void draw() const;
}

//横向转型失败
Shape *pShape1 = new Square();
Rollable *pRollable1 = dynamic_cast<Rollable *>(pShape1);//pRollable为NULL

//横向转型成功
Shape *pShape2 = new Circle();
Rollable *pRollable2 = dynamic_cast<Rollable *>(pShape2);//pRollable不为NULL

指针比较

接上面的例子,在我的机器上pShape2和pRollable2的值(所指向的地址)分别为:

pShape:     0x0039A294
pRollable:  0x0039A290

说明dynamic_cast在进行转型的时候对不同多态类型设置了不同的偏移量,接下来的问题是:

pRollable2 == pShape2
//上述比较运算c++中会报错,不允许类型不同的指针之间的比较

这个表达式应该返回什么呢?答案是:1,即指针比较相等。也许从C语言转到C++的朋友可能比较感到困惑,因为在C语言中指针的比较只是值的比较而已。显然对于多态类型,C++编译器为==运算符做了更多的幕后工作来保证指针比较注重对象的同一性而非指针的值,细节涉及到C++对象模型。

参考