强制类型转换
C++强制类型转换
C++中有四种强制类型转换操作符:static_cast
,dynamic_cast
,const_cast
,reinterpret_cast
,下面分别介绍。
1.static_cast
只完成编译时期的转换检查,主要有几个应用场合,安全性由程序员自己保证。
- 用于基类和子类之间指针或引用的转换
- 任何类型指针与void指针转换
- 空指针转换成目标指针
- 基本数据类型的转换,安全性由程序员保证,不做检查,一般将小转大(例如
int
转double
)能够保证不丢失数据
2.dynamic_cast
将一个基类对象指针(或引用)转换成派生类指针(或引用),dynamic_cast
会根据基类指针是否真正指向派生类对象来做相应处理。
dynamic_cast<typename>(expression)
该运算符将expression
转换成typename
类型。注意:typename
必须是类的指针、类的引用或者void*
,并且expression
与typename
类型保持一致,同为指针、引用或void
*
dynamic_cast
运算符可以在执行期决定真正的类型。如果 downcast 是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果 downcast 不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。转换引用时失败,会抛出std::bad_cast
异常,需要catch该异常,做相应处理
dynamic_cast
主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,dynamic_cast
和static_cast
的效果是一样的;
在进行下行转换时,dynamic_cast
具有类型检查的功能,比static_cast
更安全。
#include"stdlib.h"
#include<tchar.h> //工程文件中可直接使用,无需定义
#include<iostream>
using namespace std;
class Base
{
public:
virtual void f() {cout << "Base::f" << endl;}
void f1() {cout << "Base::f1" << endl;}
private:
double x;
double y;
};
class Derived : public Base
{
public:
virtual void f() {cout << "Derived::f" << endl;}
virtual void k() {cout << "Derived::k" << endl;}
private:
double z;
};
class Base1
{
public:
virtual void g() {cout << "Base1::g" << endl;}
void g1() {cout << "Base1::g1" << endl;}
};
class Derived1 : public Base, public Base1
{
public:
virtual void f() {cout << "Derived1::f" << endl;}
virtual void h() {cout << "Derived1::h" << endl;}
};
void Test1()
{
//对于单继承,
//如果pD真的指向Derived,用dynamic_cast和static_cast效果相同
Base* pD = new Derived;
Derived* pD1 = dynamic_cast<Derived*>(pD);
pD1->f();
pD1->k();
pD1->f1();
Derived* pD2 = static_cast<Derived*>(pD);
pD2->f();
pD2->k();
pD2->f1();
//但是如果pB不是真的指向Derived,则用dynamic_cast则返回NULL,能够更早的禁止error的发生,
//如果用static_cast虽然返回的不为NULL,但是运行时可能抛出exception。
/**/////Errorcode
//Base* pB = new Base();
//Derived* pD3 = static_cast<Derived*>(pB);
//pD3->f();
//pD3->k();
//pD3->f1();
//Derived*pD4 = dynamic_cast<Derived*>(pB);
//pD4->f();
//pD4->k();
//pD4->f1();
}
void Test2()
{
//对于多重继承,
//如果pD真的指向的是Derived1,使用dynamic_cast和static_cast都可以转化为Derived1,
//但是如果要转化为Base的兄弟类Base1,必须使用dynamic_cast,使用static_cast不能编译。
Base* pD = new Derived1;
Derived1* pD1 = dynamic_cast<Derived1*>(pD);
pD1->f();
pD1->h();
pD1->f1();
Derived1* pD2 = static_cast<Derived1*>(pD);
pD2->f();
pD2->h();
pD2->f1();
Base1* pB1 = dynamic_cast<Base1*>(pD);
pB1->g();
/**/////errorcannotcompiler
//Base1* pB2 = static_cast<Base1*>(pD);
//pB2->g();
//当然对于pB不是真的指向Derived1,想要转化为Derived1或Base的兄弟类Base1,情况与Test1中的error情况相同。
}
int _tmain(int argc, _TCHAR*argv[])
{
Test1();
Test2();
return 0 ;
}
3.const_cast
const_cast
主要作用是:修改类型的const
或volatile
属性。使用该运算方法可以返回一个指向非常量的指针(或引用)指向b1
,就可以通过该指针(或引用)对它的数据成员任意改变。
int const & i = 100;
int & m = const_cast<int&>(i);
m=200;
cout<<i<<endl;
//输出结果:
//200
4.reinterpret_cast
所有指针的值都是一个表示地址的数值,值本身的转换是没有任何问题的。“再解释”是指对指针指像的哪段内存重新解释。
可以实现不同类型指针之间的相互转换,同时也支持将指针与数字之间的转换。
float f = 0;
float* pf = &f;
int* pi = reinterpret_cast<float*>(pf);
//pi重新“解释”了pf,
以上内容引自:https://zouzhongliang.com/index.php/2019/03/12/c类型转换/