目录
1)static_cast
静态类型转换,是良性的,一般不会有风险。
用法:static_cast <类型说明符> (变量或表达式)
int b = 2;
double a = static_cast<double>(b);
主要有以下几种用法:
①、用于基本类型的转换,这种转换类似于C语言里面的强制转换。
②、任何表达式的类型转换为void。
③、父类和子类指针之间的转换。如果父类指针指向一个对象,此时将父类指针转换为子类指针是不安全的,子类指针转换为父类指针是安全的。
④、把空指针转换成目标类型的指针
注意:static_cast不能转换掉expression的const、volitale或者_unaligned属性,在类的类型转换中,只适用于有相互联系的类才可以相互转换,不一定保护虚函数。
2)const_cast
const_cast主要用来强制去掉不能修改的常量特性(常量对象的指针或者引用,不是常量对象)。
用法:cosnt_cast <类型说明符> (变量或表达式)
#include<iostream>
using namespace std;
int main()
{
const int a = 10;
const int * p = &a;
int *q;
q = const_cast<int *>(p);
*q = 20; //fine
cout <<a<<" "<<*p<<" "<<*q<<endl;
cout <<&a<<" "<<p<<" "<<q<<endl;
return 0;
}
输出结果:
10 20 20
002CFAF4 002CFAF4 002CFAF4
可以看到q p和a地址一样的,但打印的内容不一样,这是因为c++对常量的处理更像是编译期的define,是一个值替换的过程,cout << 被修改为cout<<10。
在上图中我们称“*q=20”语句为未定义行为语句,所谓的未定义行为是指在标准的C++规范中并没有明确规定这种语句的具体行为,该语句的具体行为由编译器来自行决定如何处理。对于这种未定义行为的语句我们应该尽量予以避免!
从上图中我们可以看出我们是不想修改变量a的值的,既然如此,定义一个const_cast关键字强制去掉指针的常量性到底有什么用呢?我们接着来看下面的例子。
#include<iostream>
using namespace std;
const int * Search(const int * a, int n, int val);
int main()
{
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int val = 5;
int *p;
p = const_cast<int *>(Search(a, 10, val));
if(p == NULL)
cout<<"Not found the val in array a"<<endl;
else
cout<<"hvae found the val in array a and the val = "<<*p<<endl;
return 0;
}
const int * Search(const int * a, int n, int val)
{
int i;
for(i=0; i<n; i++)
{
if(a[i] == val)
return &a[i];
}
return NULL;
}
引用也类似,使用 const_cast 进行强制类型转换可以突破 C/C++ 的常数限制,修改常数的值,因此有一定的危险性。
3)reinterpret_cast
在使用reinterpret_cast强制转换过程仅仅只是比特位的拷贝,因此在使用过程中需要特别谨慎,可以认为是static_cast的补充。
用法:reinterpret_cast <类型说明符> (变量或表达式)
int *a = new int;
double *d = reinterpret_cast<double *>(a)
主要有以下几种用法:
①、改变指针或者引用类型
②、将指针或者引用转换为一个足够长度的整型
③、将整型转换为指针或者引用类型。
4)dynamic_cast
dynamic_cast 用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。向上转型是无条件的,不会进行任何检测,所以都能成功;向下转型的前提必须是安全的,要借助 RTTI 进行检测,所有只有一部分能成功。
dynamic_cast 与 static_cast 是相对的,dynamic_cast 是“动态转换”的意思,static_cast 是“静态转换”的意思。dynamic_cast 会在程序运行期间借助 RTTI 进行类型转换,这就要求基类必须包含虚函数;static_cast 在编译期间完成类型转换,能够更加及时地发现错误。
用法:dynamic_cast <类型说明符> (变量或表达式)
demo1:
#include<iostream>
using namespace std;
class base
{
public :
void m(){cout<<"m"<<endl;}
};
class derived : public base
{
public:
void f(){cout<<"f"<<endl;}
};
int main()
{
derived * p;
p = new base;
p = static_cast<derived *>(new base);
p->m();
p->f();
return 0;
}
本例中定义了两个类:base类和derived类,这两个类构成继承关系。在base类中定义了m函数,derived类中定义了f函数。在前面介绍多态时,我们一直是用基类指针指向派生类或基类对象,而本例则不同了。
本例主函数中定义的是一个派生类指针,当我们将其指向一个基类对象时,这是错误的,会导致编译错误。
但是通过强制类型转换我们可以将派生类指针指向一个基类对象,p = static_cast<derived *>(new base);语句实现的就是这样一个功能,这样的一种强制类型转换时合乎C++语法规定的,但是是非常不明智的,它会带来一定的危险。
在程序中p是一个派生类对象,我们将其强制指向一个基类对象,首先通过p指针调用m函数,因为基类中包含有m函数,这一句没有问题,之后通过p指针调用f函数。一般来讲,因为p指针是一个派生类类型的指针,而派生类中拥有f函数,因此p->f();这一语句不会有问题,但是本例中p指针指向的确实基类的对象,而基类中并没有声明f函数,虽然p->f();这一语句虽然仍没有语法错误,但是它却产生了一个运行时的错误。换言之,p指针是派生类指针,这表明程序设计人员可以通过p指针调用派生类的成员函数f,但是在实际的程序设计过程中却误将p指针指向了一个基类对象,这就导致了一个运行期错误。
产生这种运行期的错误原因在于static_cast强制类型转换时并不具有保证类型安全的功能,而C++提供的dynamic_cast却能解决这一问题,dynamic_cast可以在程序运行时检测类型转换是否类型安全。
当然dynamic_cast使用起来也是有条件的,它要求所转换的操作数必须包含多态类类型(即至少包含一个虚函数的类)。
demo2:
#include<iostream>
using namespace std;
class base
{
public :
void m(){cout<<"m"<<endl;}
};
class derived : public base
{
public:
void f(){cout<<"f"<<endl;}
};
int main()
{
derived * p;
p = new base;
p = dynamic_cast<derived *>(new base);
p->m();
p->f();
return 0;
}
在本例中利用dynamic_cast进行强制类型转换,但是因为base类中并不存在虚函数,因此p = dynamic_cast<derived *>(new base);这一句会编译错误。为了解决本例中的语法错误,我们可以将base类中的函数m声明为虚函数,virtual void m(){cout<<"m"<<endl;}
dynamic_cast还要求<>内部所描述的目标类型必须为指针或引用。
demo3:
#include<iostream>
#include<cstring>
using namespace std;
class A
{
public:
virtual void f()
{
cout<<"hello"<<endl;
};
};
class B:public A
{
public:
void f()
{
cout<<"hello2"<<endl;
};
};
class C
{
void pp()
{
return;
}
};
int fun()
{
return 1;
}
int main()
{
A* a1=new B;//a1是A类型的指针指向一个B类型的对象
A* a2=new A;//a2是A类型的指针指向一个A类型的对象
B* b;
C* c;
b=dynamic_cast<B*>(a1);//结果为not null,向下转换成功,a1之前指向的就是B类型的对象,所以可以转换成B类型的指针。
if(b==NULL)
{
cout<<"null"<<endl;
}
else
{
cout<<"not null"<<endl;
}
b=dynamic_cast<B*>(a2);//结果为null,向下转换失败
if(b==NULL)
{
cout<<"null"<<endl;
}
else
{
cout<<"not null"<<endl;
}
c=dynamic_cast<C*>(a);//结果为null,向下转换失败
if(c==NULL)
{
cout<<"null"<<endl;
}
else
{
cout<<"not null"<<endl;
}
delete(a);
return 0;
}
参考:
C++四种类型转换运算符:static_cast、dynamic_cast、const_cast和reinterpret_cast_C语言中文网