在C语言中我们经常要做类型转换,例如malloc函数分配内存时需要从void *
转换成你指定的类型指针。如下面这样:
1 | int* block = (int*)malloc(sizeof(int)); |
上面的代码是将void*
转换成int*
,这种转换方式在C语言中称为强制转换
。它的好处是简洁,灵活;缺点是需要人来决定转换后类型是否正确,因此对开发人员的要求是很高的。
C++的四种类型转换
C++觉得C的强制转换方式不是很友好,尤其是没法通过编译器或运行时检测工具来提供帮助,光靠人的能力来判断是很不靠谱的事儿。
而且相对于C来说,分析C++程序的运行轨迹要比分析C复杂得多。因此C++提出了四种新的类型转换方法,这四种类型转换方法分别是:static_cast
、dynamic_cast
、const_cast
以及reinterpret_cast
。
下面我们就来对这四种类型转换方法做下详细讨论。
static_cast
static_cast主要用于不同类型变量之间的转换及左值转右值等。比如说double转int就需要用static_cast转换。我们来举个例子:
1 | //不同类型之间的转换 |
这里需要注意的是:int 转 double是隐式转换,右值转左值也是隐性转换,所以对这两种情况是不需要用static_cast进行显示转换的。
上面我们说的是普通类型的转换。而对于类对象来说,static_cast不能直接将一种类对象转成另一种类对象。比如:
1 | class A{ |
像上面这种用static_cast将A类型的对象转成B类型对象是不允许的。但你可以利用static_cast将基类指针/引用转成子类指针/引用。如下所示:
1 | ... |
但这里有个前提条件,即只有有父子关系的类之间才可以做如上转换,否则编译失败。还有,虽然以上两种使用static_cast的方式都可以编译通过,但用户自己要防止越界访问的问题。
static_cast除了上面讨论的几种情况外,还有一点需要牢记,即**static_cast不允许不同类型之间指针/引用的转换(有父子关系的类对象除外)**。看个具体的例子::
1 | ... |
上面的代码在编译时会报错,因为它不允许不同类型之间的指针或引用转换。对于有父子关系的类对象之间之所以可以转换是因为static_cast把它们当做同一类型看待了。
所以总结来说,static_cast主要用于不同类型变量之间的转换,指针和引用的转换不能用static_cast,而应该用reinterpret_cast。
reinterpret_cast
reinterpret_cast类似于C语言中不同类型指针间的类型转换,最接近于C的强制转换。举个例子:
1 | ... |
上面的代码是将double*
转成 int*
。如果你使用static_cast做这种转换转换是不允许的,但改用reinterpret_cast就一切正常。 当然,如果你用reinterpret_cast做static_cast善长的变量类型转换也会报错。从上面的描述我们应该知道reinterpret_cast与static_cast之间的区别了。
如果我们像下面这样用reinterpret_cast去做类型变量的转换,编译器会报错:
1 | ... |
这样的转换是绝对不允许的。
reinterpret_cast还有一个特点,它可以将指针转成长整型,也可以将长整型转成指针。如下所示:
1 | ... |
上面是将一个int*
转成long型,又将long型转成double*
,这些都是reinterpret_cast善长做的转换。
reinterpret_cast对于对象指针/引用的转换与普通类型的指针/引用转换是一样的。因此不同类型的对象指针/引用可以随意转换,但转换后是否会引起问题它不关心,这要由开发人员自己保证。
1 | A * pa = new A(); |
总结一下,reinterpret_cast是对指针/引用的转换,其中必须至少有一个是指针或引用,否则它会报错。
const_cast
这个比较简单,它的作用是去掉指针/引用中的const限制。这里要注意的是被转换的一定是指针/引用的const,而常数的const是不能去掉的。举个例子:
1 | ... |
上面的代码是想通过const_cast将常数的const去掉?这是决对不可以的!!!编译器一定会报错。
而如果是加了const的指针/引用就没问题了,我们再来一个列子:
1 | ... |
将一个const 指针转换成非const指针正是const_cast做的事儿。
我们再来想一种case,是否可以将一种类型的const指针转换成另一种类型的非const指针呢?如下所示:
1 | ... |
这样也是不允许的。对于const_cast来说,它只能将同一类型的const 指针/引用 转成非const指针/引用。
所以我们这里总结一下,const_cast是一个专门去掉同一类型的const限制的类型转换方法。它不如static_cast和reinterpret_cast应用的广泛。
dynamic_cast
这个转换方法限制比较多,一、它只能处理类对象;二、它只能处理指针;三、它只能用于将子对象转换成父对象这样的操作。我们来看一个例子:
1 | ... |
只有上面这一种情况可以编译成功,其它情况都会失败!
小结
下面我们总结一下这四种类型转换方法。四种转换方法中,用的比较多的是static_cast和reinterpret_cast这两种转换方法。
static_cast主要用于普通类型变量的转换,如double到int的转换,或左值转右值。当然它也可以在父对象与子对象之间进行指针转换。
reinterpret_cast主要用于不同类型指针/引用间的转换。也可以将指针/引用转成长整型或将长整型转成指针类型。但不可以像static_cast一样在两个不同的类型变量间转换。也就是说reinterpret_cast在转换时必须有一个是指针/引用。
const_cast就比较简单了,它只能将同一类型的const指针转成同一类型的非const指针。
dynamic_cast只能用于有父子关系的类对象之间的转换,而且只能用于将子对象转换成父对象。