C语言中实现了基本类型的转换机制,比如int转double,char转int等等。转换的格式也很简单
(转换类型)变量
或者
转换类型(变量)
在C语言中这种方法很简洁高效,可以对任意类型做强制转换,但缺点也是不少,比如double转int的时候会出现精度损失。
当到了C++
的时候,因为类类型及C++
的多态等机制,使得一个对象的内存结构可以变得很复杂,显然C风格的简单粗暴的类型转换机制会为C++程序带来很大的风险。
比如父类对象向子类类型转型,是不安全的转换,但是C风格的转换却是可以通过的。
因此C++的标准中,实现了4种类型转换符,不仅兼容C的基本类型,还能适用于类类型的转换,并且根据需求场景的不同,使用相对应的类型转换符可以有效提高程序的健壮性和可维护性。
具体的形式如下:
cast(expression)
类型转换符<目标转换类型>(被转换变量)
如果type是引用类型的话转换的结果是一个左值。
①static_cast
static_cast是最常用的类型转换符,作用类似于C风格的强制转换,一般建议C++程序中使用static_cast代替传统的C风格转换。因为作用是类似于C风格的强制转换也就是说static_cast不会进行运行时的类型检查,转换不一定是安全的。
同时static_cast的转换不会去除变量的const、volatile、或者__unaligned属性。
用法示例
int interger;
double Double=6.7777;
interger = static_cast<int>(Double);//6
简单总结一下就是,static_cast其实和C风格的功能是一样的,只是在转换的时候编译器不会出现警告信息。使用static_cast的时候我们程序员需要自行判断转换的安全性。
②const_cast
这一个运算符是比较有意思的,可以消除一个被const/volatile符号修饰的变量的const/volatile属性。嗯,我们只看const的话,可以发现C++提供了一个剥夺常量的常量属性的操作,看起来好矛盾,为什么要这样做不会很多余吗?个人觉得这个运算操作的存在,贯彻了C++之父对C++的设计理念,不让语言本身的特性成为限制程序员拦路虎,限制思维。所以在C++中存在一个剥夺常量的常量属性的操作是合理的。
以下是C++primer第五版中给出的例子
const char *pc;
char *p=const_cast<char*>(pc);//正确:但通过p写值是未定义的行为
然后下面是我写的例子
const int a=3;
int &b = const_cast<int&>(a);
b = 4;
cout<<a<<" "<<&a<<endl;//3 0x73fe44
cout<<b<<" "<<&b<<endl;//4 0x73fe44
嗯,可以发现去掉了a的const属性后的却可以通过b在写值,但是呢并未改变原实体a的值,这就是书中所指的未定义行为?相同的地址可以输出不同的值,比较玄学,个人估计应该是程序对指向同一地址的不同的符号都有保留一个副本或者是记录了和实体之间的转换操作(当然也未必是如此)。const_cast可以用于一种用来编写特别的函数如下:
string& shorter(const string str1,const string str2)
{
return str1.size()<str2.size()?const_cast<string&>(str1):const_cast<string&>(str2);
}
可以不创建额外的副本,就可以返回两个const输入的字符串的较小者。基本const_cast也就这个用途用的多。
③reinterpret_cast
reinterpret_cast按照字面意思来看,重新解释,意思就是它可以对任意的无关类型之间进行转换,也就是新旧类型都有相同的二进制值,但程序对这一段二进制值解释的意义缺不一样,这就很厉害了。下面是我在网上查阅到的一个比较好的博客
C++标准转换运算符reinterpret_cast
。
总之一句话,这一个转换符慎用。
④dynamic_cast
顾名思义:动态转换。dynamic_cast是4种转换运算符中唯一一个在运行时进行类型转换的运算符,配合另一个typeid运算符使用就可以手工实现人们常说的RTTI(运行时类型识别)。
dynamic_cast的使用如下:
dynamic_cast
Base *pb;
Derived *pd = dynamic_cast<Derived*>(pb);
关于dynamic_cast能够进行运行时类型检查的原理背后,也有前人去探究了一下。可以看这篇博文C++ dynamic_cast实现原理
参考资料:
百度百科
C++primer第5版等