在C语言中我们经常要做类型转换,例如malloc函数分配内存时需要从void *
转换成你指定的类型指针。如下面这样:
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转换。我们来举个例子:
//不同类型之间的转换
double d = 10.1;
int i = static_cast
//左值转右值
int lv = 10;
int && rv = static_cast
这里需要注意的是:int 转 double是隐式转换,右值转左值也是隐性转换,所以对这两种情况是不需要用static_cast进行显示转换的。
上面我们说的是普通类型的转换。而对于类对象来说,static_cast不能直接将一种类对象转成另一种类对象。比如:
class A{
public:
int a;
};
class B:public A {
public:
int b;
};
class C {
public:
int c;
};
int main(int argc, char *argv[]){
A a;
B b;
b = static_cast(a); //不允许static_cast将一个对象转成另一个对象
}
像上面这种用static_cast将A类型的对象转成B类型对象是不允许的。但你可以利用static_cast将基类指针/引用转成子类指针/引用。如下所示:
...
A ca;
B & crb = static_cast(ca);
...
A * pa = new A();
B * cpb = static_cast(pa);
...
但这里有个前提条件,即只有有父子关系的类之间才可以做如上转换,否则编译失败。还有,虽然以上两种使用static_cast的方式都可以编译通过,但用户自己要防止越界访问的问题。
static_cast除了上面讨论的几种情况外,还有一点需要牢记,即static_cast不允许不同类型之间指针/引用的转换(有父子关系的类对象除外)。看个具体的例子::
double *pd = new double();
int * pi = static_cast(pd); //报错
上面的代码在编译时会报错,因为它不允许不同类型之间的指针或引用转换。对于有父子关系的类对象之间之所以可以转换是因为static_cast把它们当做同一类型看待了。
所以总结来说,static_cast主要用于不同类型变量之间的转换,指针和引用的转换不能用static_cast,而应该用reinterpret_cast。
reinterpret_cast
reinterpret_cast类似于C语言中不同类型指针间的类型转换,最接近于C的强制转换。举个例子:
double *pd = new double();
int * pi = reinterpret_cast(pd);
上面的代码是将double*
转成 int*
。如果你使用static_cast做这种转换转换是不允许的,但改用reinterpret_cast就一切正常。 当然,如果你用reinterpret_cast做static_cast善长的变量类型转换也会报错。从上面的描述我们应该知道reinterpret_cast与static_cast之间的区别了。
如果我们像下面这样用reinterpret_cast去做类型变量的转换,编译器会报错:
double d = 10.1;
int i = reinterpret_cast(d);
这样的转换是绝对不允许的。
reinterpret_cast还有一个特点,它可以将指针转成长整型,也可以将长整型转成指针。如下所示:
int a = 10;
long ll = reinterpret_cast(&a);
double *dd = reinterpret_cast(ll);
上面是将一个int*
转成long型,又将long型转成double*
,这些都是reinterpret_cast善长做的转换。
reinterpret_cast对于对象指针/引用的转换与普通类型的指针/引用转换是一样的。因此不同类型的对象指针/引用可以随意转换,但转换后是否会引起问题它不关心,这要由开发人员自己保证。
A * pa = new A();
B b;
B & rb = B();
C * cc = reinterpret_cast(pa);
C & rcc = reinterpret_cast(rb);
总结一下,reinterpret_cast是对指针/引用的转换,其中必须至少有一个是指针或引用,否则它会报错。
const_cast
这个比较简单,它的作用是去掉指针/引用中的const限制。这里要注意的是被转换的一定是指针/引用的const,而常数的const是不能去掉的。举个例子:
const int a = 10;
int b = const_cast(a);
上面的代码是想通过const_cast将常数的const去掉?这是决对不可以的!!!编译器一定会报错。
而如果是加了const的指针/引用就没问题了,我们再来一个列子:
const int * pca = new int(10);
int * pa = const_cast(pca);
将一个const 指针转换成非const指针正是const_cast做的事儿。
我们再来想一种case,是否可以将一种类型的const指针转换成另一种类型的非const指针呢?如下所示:
const int * pca = new int(10);
double * pa = const_cast(pca);
这样也是不允许的。对于const_cast来说,它只能将同一类型的const 指针/引用 转成非const指针/引用。
所以我们这里总结一下,const_cast是一个专门去掉同一类型的const限制的类型转换方法。它不如static_cast和reinterpret_cast应用的广泛。
dynamic_cast
这个转换方法限制比较多,一、它只能处理类对象;二、它只能处理指针;三、它只能用于将子对象转换成父对象这样的操作。我们来看一个例子:
A * a;
B * b =new B();
a = dynamic_cast(b);
只有上面这一种情况可以编译成功,其它情况都会失败!
小结
下面我们总结一下这四种类型转换方法。四种转换方法中,用的比较多的是static_cast和reinterpret_cast这两种转换方法。
static_cast主要用于普通类型变量的转换,如double到int的转换,或左值转右值。当然它也可以在父对象与子对象之间进行指针转换。
reinterpret_cast主要用于不同类型指针/引用间的转换。也可以将指针/引用转成长整型或将长整型转成指针类型。但不可以像static_cast一样在两个不同的类型变量间转换。也就是说reinterpret_cast在转换时必须有一个是指针/引用。
const_cast就比较简单了,它只能将同一类型的const指针转成同一类型的非const指针。
dynamic_cast只能用于有父子关系的类对象之间的转换,而且只能用于将子对象转换成父对象。
另外别人总结:
- 一
作者:灵剑
链接:https://www.zhihu.com/question/400931816/answer/1289350843
来源:知乎
为什么说 C++ 的四种命名类型转换比旧式转换更安全?
- C中的指针转换永远都是保持指针指向地址不变,只改变指针类型,因此C中的C-Cast其实是没有歧义的。但在C++中,指针之间的自动转换存在一种特殊情况:如果将子类指针转向基类指针类型,这时候有可能需要调整指针指向的地址,尤其是多继承的情况下。但是,也有可能用户就是想要旧式的强制改变类型而不改变值的特性,使用C-Cast就会比较麻烦,而且如果用户想要子类基类转换,却不小心搞错了继承关系,也会自动变成reinterpret_cast,这样还不如将这两种可能的转换方式分开,指针强制转换用reinterpret_cast表示,基类子类转换用static_cast表示,这样如果指针之间没有基类子类关系而用了static_cast就能正确提示编译错误,也避免了语义上的歧义。
- C++比起C来说大大增强了const的作用,也允许const常量参与编译器优化,因而也需要对const修饰进行更强的保护。C-Cast可以自由去掉const限制,而在许多情况下去掉const修饰都是很危险的,实际使用中也很少出现,所以将涉及const的转换单独分离出去,保证了不会在不注意的时候不小心丢掉const修饰。
- C++新引入了从基类指针向子类指针转换的功能,这种转换同样需要调整指向的地址,但跟子类向基类转换还有不同,首先基类指针不一定是子类指针,其次涉及到虚基类的时候,两个指针之间的相对偏移是不固定的,跟实际的类型有关系,这样static_cast只能处理确信基类指针是子类指针且不涉及虚继承的情况。C++需要引入一套基于运行时类型检查进行cast的方法,而且这种cast机制跟老的static_cast有歧义,所以需要引入一种新的dynamic_cast。总结来说,新的四种转换语法主要是为了保证转换语义无歧义。
- 二
作者:牛客网
链接:https://zhuanlan.zhihu.com/p/30996101
来源:知乎
四种类型转换(cast)的关键字详解及代码
1.static_cast
最常用的类型转换符,在正常状况下的类型转换,如把int转换为float,如:int i;float f; f=(float)i;或者f=static_cast
2.const_cast
用于去除const属性,把const类型的指针变为非const类型的指针,如:const int *fun(int x,int y){} int *ptr=const_cast
3.dynamic_cast
(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换。
(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,指针转换失败的话则会返回NULL,引用转换失败抛出异常。
(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。
该操作符用于运行时检查该转换是否类型安全,但只在多态类型时合法,即该类至少具有一个虚函数。dynamic_cast与static_cast具有相同的基本语法,dynamic_cast主要用于类层次间的安全的上行转换和下行转换或跨系转型。在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
4.reinterpret_cast
这个操作符与编译平台息息相关,不具备移植性
常用于转换函数指针类型。假设有一个数组存储是函数指针,有特定类型。把其他类型的函数指针放入这个数组。 避免使用
interpret是解释的意思,reinterpret即为重新解释,此标识符的意思即为数据的二进制形式重新解释,但是不改变其值。如:int i; char *ptr="hello freind!"; i=reinterpret_cast
http://www.cnblogs.com/BeyondAnyTime/archive/2012/08/23/2652696.html
http://www.cnblogs.com/carsonzhu/p/5251012.html
c++ RTTI(运行时类型识别)
http://www.cnblogs.com/zhuyf87/archive/2013/03/15/2960899.html
http://www.cnblogs.com/nliao/archive/2012/12/10/2811401.html
http://blog.csdn.net/ljianhui/article/details/46487951