第十五章之(四)类型转换运算符

类型转换运算符,共计有4个:

①dynamic_cast;

②const_cast;

③static_cast;

④reinterpret_cast;

 

第一种dynamic_cast,用于将派生类指针转化为基类指针,前提是派生类指针指向的对象,对于基类是安全的。

 

 

const_cast:

第二种是const_cast,该运算符用于执行只有一种用途的类型转换,即改变值为const或者volatile(前者是不允许被改变,后者是允许在const里被修改)。

简单来说,假如一个const指针指向了一个对象,那么使用这个指针是不能修改对象的值的(但是可以修改指向的对象);

 

在这种情况下,假如用另外一个指针,指向当前指针,会发生两种情况:

(1)使用非const指针指向这个const指针,即使类型一样,也无法成功赋值(编译器提示错误);

(2)使用另一个const指针指向他,可以实现。

 

但假如,因为某种需求(比如说,需要通过另一个指针来指向这个const指针,以修改const指针指向的地址的值),那么,显然只能用非const指针了(只有非const指针才能修改指向的值),因此用一个非const指针指向这个const指针。

矛盾出现了,非const指针不能指向一个const指针,因此必须使用const_cast运算符。

其格式为:

类型* 指针名 = const_cast <类型*> (另一个被限定的指针名);

 

例如:

         inta=1;

         constint*b = &a;

         int*c = const_cast<int*>(b);

这段代码的作用,即是让非const指针指向了一个const类型的int指针b;

 

另外,也可以让一个const指针,指向一个volatile指针,如代码:

         inta=1;

         volatileint*b = &a;

         constint*c = const_cast<constint*>(b);

 

适用于类对象:

同样,不仅可以用于基本类型,还可以用于自定义的类。

例如有一个Student类,使用一个const限定的Student类指针pr,指向了一个创建的Student对象。那么,可以通过const_cast运算符,创建另一个指针pd,指向pr指向的Student类对象。便可以通过pd来修改pr指向的对象的值。

 

不能修改const限定的对象的值:

如代码:

         constinta=1;

         constint*b = &a;

         int*c = const_cast<int*>(b);

         *c =2;

         cout <<a << endl;

虽然编译不会提示错误,但其输出的结果依然为1,而不是2。

 

不适用于不同类对象:

例如,const指针pr指向Student类对象,而指针pd是Teacher类,那么,就无法将pr通过const运算符赋值给pd。

 

 

static_cast:

第三种是static_cast运算符。

按照搜索得到的资料,static_cast运算符和dynamic_cast运算符类似。

假如有基类A,其派生类B,那么代码:

         A* a;

         B *b1 = dynamic_cast<B*>(a);        //前提是类A和类B必须有多态(即虚函数)

         B *b2 = static_cast<B*>(a);

 

区别①:b1那行代码成立的前提是,多态的存在(即虚函数,至少A有一个虚函数),而b2那行代码则不需要。

区别②:dynamic_cast运算符,如果转换失败,则返回的是一个空指针(可以用代码进行判断),static_cast,如果转换失败,编译时不会出错,但运行时会出错(不像dynamic_cast那样返回空指针)

区别③:dynamic_cast的开销比static_cast的开销大;

区别④:dynamic_cast在编译时执行转化,而static_cast在运行时执行转换。

 

static_cast运算符出错的条件:

①假如A类和B类毫无关系(不存在派生和继承关系),那么会出错;

②假如指针a,指向的不是一个B的实例(B类对象),那么也会出错;

 

问题:假如A类是基类,B类和C类分别是A类的派生类,那么,

         A* a = new C;

         B *b1 = dynamic_cast<B*>(a);        //前提是类A和类B必须有多态(即虚函数)

         B *b2 = static_cast<B*>(a);

为什么这两行代码都不会出错呢?

 

static_cast的其他用途:

①将空指针转化为其他类型的空指针,如代码:

         void*a = 0;

         int*b = static_cast<int*>(a);

②将任何类型的表达式转换为void类型;

         int*a = 0;

         void*b = static_cast<void*>(a);

③用于基本类型的转换(但需要程序员自己来保证安全);

 

补充:我查的某个资料说,这个运算符,好像并没有什么用。。

 

reinterpret_cast:(这个不明白)

第四种是reinterpret_cast

作用:是用来处理无关类型之间的转换;它会产生一个新的值,这个值会有与原始参数(expressoin)有完全相同的比特位。

不懂,反正感觉意思就是,跟bit相关的,但具体不明白。

特点是,转换时,不允许删除const,但会进行一些敏感的操作(容易出错的操作)。依赖于底层,通常不可移植。

以书上给的例子为例:

struct m

{

         shorta;

         shortb;

};

         longq = 0xA224B118;

         m*p = reinterpret_cast<m*>(&q);

         cout <<hex << p->a;

输出结果为:b118(即q的前4位——》低位的四位);

 

何时使用:

①从指针类型(因为指针存的是地址)到一个足够大的整数类型(否则存不下)

②从整数类型或者枚举类型到指针类型(位数少到位数多是没损失的)

③从一个指向函数的指针到另一个不同类型的指向函数的指针(不懂为什么用)

④从一个指向对象的指针到另一个不同类型的指向对象的指针(同上)

⑤从一个指向类函数成员的指针到另一个指向不同类型的函数成员的指针

⑥从一个指向类数据成员的指针到另一个指向不同类型的数据成员的指针

以上都不太明白

 

其作用:

可以无视类型之间的隔离(例如不同类型之间,很可能是不能转换的。例如不同类),但使用这个就可以(可以编译和运行)。

唯一的问题是,程序员需要对其进行负责,保证其一定能用,否则在运行时会出错。

参考链接:

http://blog.csdn.net/jfkidear/article/details/7718651

 

你可能感兴趣的:(const_cast,dynamic_cast,static_cast)