C++的创始人看不下去这种没有意义的类型转换,更不能容忍他们在C语言中竟然被接受。。。他觉得C语言太宽松了。于是,他提出要更严格地限制允许的类型转换,把类型转换规范化,于是添加了4个类型转换运算符。
这四个运算符,相比于通用类型转换,更加明确,更加安全。
对volatile限定符的移除不了解,不说。
只可以移除const,即把const转为非const,不可以把非const转为const
const_cast <type_name> (expression)//type_name和expression的类型必须相同
原来非const可以直接称呼为volatile,我以前还一直称呼为非const 。
这个理解对吗???
示例:
High bar;
const High * pbar = &bar;
High * pb = const_cast<High *> (pbar);//const High *->High *,删除const标签
如果还想做别的,const_cast就做不到了,它只能改变值为const或volatile。
const Low * pl = const_cast<const Low *>(pbar);//无效,因为pbar是High *,这个操作想要把pbar转换为const,同时还要转换为Low *
High bar;
const High * pbar = &bar;
High * pb = (High *) (pbar);//const High * -> High *
Low * pl = (Low *) (pbar); //const High * -> Low * ,不只修改了const,还改了类型
正是这种同时改变类型的操作,很危险,所以尽量使用const_cast运算符
//const_cast.cpp
#include
using std::cout;
using std::endl;
void change(const int * pt, int n);
int main()
{
int pop1 = 38383;
const int pop2 = 2000;
cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
change(&pop1, -100);
change(&pop2, -100);
cout << "pop1, pop2:" << pop1 << ", " << pop2 << endl;
return 0;
}
void change(const int * pt, int n)
{
int * pc;
pc = const_cast<int *>(pt);//pc是int *
*pc += n;//传入的值加上n
}
可以看到,第一个值pop1成功被修改了,但是pop2却没有被修改。这是因为,pop1本身不是const的,传入change函数后,成为了const形参
相当于是,const_cast通过这种方式打破了形参的const的保护,把原本是非const的数值还是成功修改了。但是如果数据本身就是货真价实的非const,即不允许改变的 ,则const_cast不会再造作,而是会很配合编译器,不允许转换为非const的,所以const_cast是有一个识别判断规则的,不是傻乎乎转,而要看看到底能不能转,转了安不安全,如果不安全,比如人家本来就是const的,他就不会把人家转为非const的,它不会同意这种不安全的转换。
pop1, pop2: 38383, 2000
pop1, pop2:38283, 2000
这个示例展示了const_cast的真正的用武之地:本身不是const的变量传给了一个形参设置为const引用类型的函数,这时候可以在函数内部用const_cast实现对原变量的修改。除此之外,其实用处好像很少,毕竟我们已经证明,不可能通过const_cast修改真正的const变量的值。
int main()
{
const int a = 10;
int * b = &a;//C,C++的所有标准都报错
cout << a << endl;
*b = 20;
cout << a << endl;
return 0;
}
下面的代码编译可以通过,但是a的值不会被改变,所以非常安全
int main()
{
const int a = 10;
cout << a << endl;
int * c = const_cast<int *> (&a);
*c = 20;
cout << a << endl;
return 0;
}
这个示例说明,C++里面,const就是const,你不管什么招数办法,都改不了const变量的值,所以非常安全。
10
10
static_cast和dynamic_cast主要是解决类的继承层次中类型转换的安全性。static_cast是在编译时检查,不再运行时进行类型检查,所以是静态的;而dynamic_cast是在运行时进行类型检查,所以保证了安全性。
static_cast <type_name> (expression)//type_name和expression的类型必须相同
High bar;
Low blow;//Low是从High继承来的
High * pb = static_cast<High *> (&blow);//upcast,向上转换
Low * pl = static_cast<Low *> (&bar);//downcast,向下转换
Pond * pmer = static_cast<Pond *> (&blow);//无效,因为Pond是无关的类
第一种是派生类转为基类,属于向上转换,可以,用不用static_cast都行。
其中第二种转换是把High *
转为Low *
,基类转为派生类,是向下的转换,如果不用static_cast,是根本不允许的。
向下转换只有用static_cast才允许。
用于类层次间的向上和向下转化,static_cast可以实现类层次的向下转换但是不安全,所以不要用。
上一篇文章说过了。它用来把一种类型的指针转换为另一种类型的指针,如果可以实现安全转换的话就转,不能安全转换就不转,而返回一个空指针。
向下转化时,如果是非法的对于指针返回NULL,对于引用抛异常。要深入了解内部转换的原理。
向上转换:指的是子类向基类的转换
向下转换:指的是基类向子类的转换
dynamic_cast <type_name> (expression)
pl = dynamic_cast<Low *> ph;//如果ph可以转换为Low类型的指针,则会把转换得到的Low指针赋给pl,否则赋空指针
那什么叫做能安全转换呢?
在类层次中向上转换(is-a继承关系),就是安全的转换。
reinterpret_cast <type_name> (expression)//type_name和expression的类型必须相同
几乎什么都可以转,比如将int转指针,可能会出问题,尽量少用;相当于是明明可能有错,但是你还是非要转就用这个,当然是尽量不要用了
不允许删除const
但会执行其他令人生厌的操作(有时候程序员必须得做这种依赖于实现的令人生厌的操作)
不支持所有的类型转换
但在C语言,这些转换都可以。。所以C++的类型转换限制比C严格很多。