恩,这四个cast,之前一直没怎么搞懂,在使用类型转化时仍然经常使用C风格的转化,而且之前的一次笔试题竟然考的就是这道题,好吧,我强迫症又犯了,一定要彻底搞懂...
一.概述
1.(typename)element:C风格的强制转化,貌似通吃,但是既然用了C++,还有分门别类的cast,是时候放弃这个了。
2. static_cast<typename>(element):通常转换,没有运行时的检测,在不知道用哪个的时候用这个就好了。
3. dynamic_cast<typename>(element) :动态转换,有运行时检测,通常在基类和派生类之间转换时使用。
4. const_cast<typename>(element):主要针对const和volatile的转换,去除const属性
5. reinterpret_cast<typename>(element):用于没有任何关联的类型转换,慎用
俗话说得好,实践是检验真理的唯一标准,要想清楚的知道每种转化会发生什么,最好的办法就是写个demo,而不是看别人的blog怎么写,自己就怎么说,这样印象不深刻,而且可能人云亦云,没有自己的想法。
二.static_cast
关于static_cast,最常用的一个转化,当我们不知道用哪个cast的时候,static_cast是最好的选择。但是这个转换没有运行时类型检查保证转换的安全性。允许任意的隐式转换以及相反的转换动作。具体的转化功能如下:
1.基本数据类型之间的转化,如Int转化为char之类的
2.void*类型的指针转化为其他类型的指针
3.其他类型的指针转化为void*类型的指针
4.子类指针转化为父类指针(向上转型,安全,不写static_cast也会发生隐式转换)
5.父类指针转化为子类指针(向下转型,不一定安全,如果调用子类特有字段属性会出错)
注意:
1.static_cast不能转换掉const,volitale属性
2.在基本的类型或者上下转型时,被转化的对象和要转化成的对象要类型一致,如果在两个不相干的类型中转化,会编译出错。
好的,下面是针对这5点的一个例子:
// C++Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
class CastTestBase
{
public:
CastTestBase(string n):name(n)
{
}
~CastTestBase()
{
}
void ShowBase()
{
cout<<"show base, name is : "<<name<<endl;
}
private:
string name;
};
class CastTestChild : public CastTestBase
{
public:
CastTestChild(string n, string cn) : CastTestBase(n), childname(cn)
{
}
~CastTestChild()
{
}
void ShowChild()
{
cout<<"show child, name is: "<<childname<<endl;
}
private:
string childname;
};
void TestFunc1(int* num)
{
cout<<"num is "<<*num<<endl;
}
void TestFunc2(void* pointer)
{
cout<<"num is "<<(*static_cast<int*>(pointer))<<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
//static_cast转换内置数据类型
int a = 10;
char b = static_cast<char>(a);
//void*型指针转化为其他类型指针
void* pointer = new int(1);
TestFunc1(static_cast<int*>(pointer));
//其他任何类型指针转化为void*型指针
int* num = new int(2);
TestFunc2(num);
//子类指针转化为父类指针(安全,不写static_cast也可以执行隐式转换)
CastTestBase* basePointer = static_cast<CastTestBase*>(new CastTestChild("child", "child"));
basePointer->ShowBase();
//父类指针转化为子类指针(不一定安全,如果调用子类特有的内容会出错)
CastTestChild* childPointer = static_cast<CastTestChild*>(new CastTestBase("base"));
//childPointer->ShowChild();//这样会出错的,父类并没有childname字段。而如果只调用函数没有问题,使用字段会出现问题
childPointer->ShowBase();
system("pause");
return 0;
}
结果:
num is 1
num is 2
show base, name is : child
show base, name is : base
请按任意键继续. . .
num is 2
show base, name is : child
show base, name is : base
请按任意键继续. . .
//childPointer->ShowChild();//这样会出错的,父类并没有childname字段。而如果只调用函数没有问题,使用字段会出现问题
这句如果运行,会有问题,即编译不会出错,不会检查类型转换的问题,在运行时直接崩掉。
三.dynamic_cast
从字面上理解是动态转化,其实就是增加了运行时检查的机制,如果转化不对,在运行时会返回一个空指针,我们可以通过判断转化的结果是否为空来判断转化是否成功,而不会像static_cast一样直接崩掉。不过,既然加了运行时检查,在运行时肯定会有性能的损失。
dynamic_cast运用于下面的情况:
只能用于指针或者引用,主要用于执行带有安全检测的向上转型或者向下转型,不过向上转型可以有隐式转化,并且是安全的,所以主要是用于向下转型的检测。
1.基类有虚函数时,可以向上或者向下转型,在向下转型时可以判断转换是否能返回一个完整的对象,在运行时检测。如果有问题,返回一个空指针
2.基类没有虚函数时,只能进行向上转型,然而向上转型并不需要dynamic_cast,隐式转化也可以,否则编译出错。
// C++Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
class CastTestBase
{
public:
CastTestBase(string n):name(n)
{
}
~CastTestBase()
{
}
void ShowBase()
{
cout<<"show base in base, name is : "<<name<<endl;
}
virtual void ShowChild()
{
cout<<"show child in base"<<endl;
}
private:
string name;
};
class CastTestChild : public CastTestBase
{
public:
CastTestChild(string n, string cn) : CastTestBase(n), childname(cn)
{
}
~CastTestChild()
{
}
virtual void ShowChild() override
{
cout<<"show child in child, name is: "<<childname<<endl;
}
private:
string childname;
};
int _tmain(int argc, _TCHAR* argv[])
{
//子类指针转化为父类指针(安全,不写static_cast也可以执行隐式转换)
CastTestBase* basePointer = dynamic_cast<CastTestBase*>(new CastTestChild("child", "child"));
basePointer->ShowBase();
basePointer->ShowChild();
//父类指针转化为子类指针(不一定安全,如果调用子类特有的内容会出错)
CastTestChild* childPointer = dynamic_cast<CastTestChild*>(new CastTestBase("base"));
if (childPointer)//dynamic_cast的返回值可能是NULL,切记!!!
{
childPointer->ShowBase();
childPointer->ShowChild();//这样会出错的,父类并没有childname字段。而如果只调用函数没有问题,使用字段会出现问题
}
else
cout<<"dynamic_cast failed!"<<endl;
system("pause");
return 0;
}
show base in base, name is : child
show child in child, name is: child
dynamic_cast failed!
请按任意键继续. . .
show child in child, name is: child
dynamic_cast failed!
请按任意键继续. . .
这里,由于和上面static_cast一样的原因,showchilid本应该出错,但是在转化过程中,dynamic_cast判断出了转化会出问题,所以直接返回了一个空指针,让我们可以根据这个进行处理,就避免了程序直接莫名的崩溃...
四.const_cast
用于修改类型的const或者volatile属性,类型不会有变化,只是去掉前面的修饰符。
int _tmain(int argc, _TCHAR* argv[])
{
const int a = 10;
//a = 20;不能修改常量
//int b = const_cast<int>(a);<>中的即要转化的对象必须是指针或者引用
int* b = const_cast<int*>(&a);
//int* b = &a;const int 类型的实体不能使用int*类型的指针指向
*b = 20;
cout<<*b<<endl;
//int& c = a;非const引用不能引用const变量
int& c = const_cast<int&>(a);
c = 30;
cout<<c<<endl;
system("pause");
return 0;
}
使用const_cast时要注意,const_cast并非直接修改变量,而是只能通过指针或者引用来去除const限定符,即
const_cast的<>中只能接受引用或者指针类型的对象。不能直接放入数据类型。转换之后仍然指向或者引用原来的对象,但是常量对象被转化为非常量对象。
C++有const类型,就是让我们不改变变量的内容,但是还是提供了去除这一个限制的方法,可见C++的灵活!!!
五.reinpreter_cast
这个最简单粗暴...甭管是啥,都能转。类型可以是指针,引用,基本数据类型,函数指针,或者成员指针。甚至可以将int转化为一个指针...这种转化根本不会检查转化的合理性,只是拷贝数据,强制转化。
这个东东还是慎用吧,如果他说什么都能干,感觉可能什么都干不好...还是术业有专攻的好...
参考链接:http://m.blog.csdn.net/blog/pizi0475/46794631
http://blog.csdn.net/starryheavens/article/details/4617637