强制转换
强制转换

类型转换有c风格的,当然还有c++风格的。c风格的转换的格式很简单
TYPE a = (TYPE)EXPRESSION;
但是c风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型之间转换,比如你可以把一个指向const对象的指针转换成指向非const对象的指针,把一个指向基类对象的指针转换成指向一个派生类对象的指针,这两种转换之间的差别是巨大的,但是传统的c语言风格的类型转换没有区分这些。 另一个缺点就是,c风格的转换不容易查找,它由一个括号加上一个标识符组成,而这样的东西在c++程 序里一大堆。 c++为了克服这些缺点,引进了4个新的类型转换操作符(非函数),他们是static_cast,const_cast,dynamic_cast,reinterpret_cast
static_cast
的类型转换,最常用的类型转换符,在正常状况下的类型转换, 用于将一种基本数据类型转换成另一种基本数据类型,如把int转换为float
int iNumber = 100;
float fNumber = 0;
fNumber = (float) iNumber;//C风格
fNumber = static_cast<float>(iNumber);
也可以完成指针之间的转换,例如可以将void*指针转换成其他类型的指针
void *pVoid = malloc(sizeof(int));
int *pInt = static_cast<int*>(pVoid);
*pInt = 1;
但
int iNumber = 1;
int *pInt = &iNumber;
float *pFloat = static_cast<float *>(pInt);//error
总结,static_cast的用法主要有以下几种:
- 用于基本数据类型之间的转换,如把int转成char,把int转成enum。这种转换的安全性也要开发人员来保证。
- 把void指针转换成目标类型的指针,但。
- 把任何类型的表达式转换成void类型。
- 用于类层次结构中基类和派生类之间指针或引用的转换。进行上行转换(把;进行下行转换(把。
const_cast
该运算符。常量指针被转化成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。
const int number = 100;
int *pInt = &number; //error
int *pInt1 = (int*)&number; //C中类型转换
int *pInt2 = const_cast<int *>(&number); //C++中类型转换const_cast
注意:
不考虑const或valatile,才可以进行合理的类型转换。
转换为相同类型的时候,我们通过反汇编查看时候,发现**与所生成的的**。

但是在转换成汇编指令之前,即编译阶段,就有所不同。
注意1:不考虑const或valatile后,类型保持一致才可以进行合理的类型转换
const int a = 10;
char *p1 = (char*)&a;//C中类型转换,可以
char *p2 = const_cast<char*>(&a);//C++中类型转换const_cast,不可以
如果通过C中类型转换可以将int * 转换为多种不同的类型,没有任何问题;这里为整型常量的地址,但是如果通过const_cast将整型常量地址转换为另一个指针类型不匹配的指针,是不可以的。。防止了C中低级别的类型强转任意的转换指针的类型导致一些不确定的错误。
注意2:const_cast<里面必须是指针或引用类型>,否则出错,例如:
const int a = 10;
int b = const_cast<int>(a);
dynamic_cast
该运算符主要用于基类和派生类间的转换,尤其是向下转型的用法中。
,用于继承结构中,可以支持RTTI类型识别的上下转换及识别。将一个基类对象指针(或引用)转换到继承类指针,
class Base
{
public:
virtual void func() = 0;
};
class Derive1 : public Base
{
public:
void func()
{
cout << "call Derive1::func" << endl;
}
};
class Derive2 : public Base
{
public:
void func()
{
cout << "call Derive2::func" << endl;
}
};
void showFunc(Base* p)
{
p->func();//动态绑定
}
int main()
{
Derive1 d1;
Derive1 d2;
showFunc(&d1);
showFunc(&d2);
return 0;
}
但是,我们的需求改变了。Derive实现了一个新功能的API接口函数
class Derive2 : public Base
{
public:
void func()
{
cout << "call Derive2::func" << endl;
}
//需求更改 Derive2实现新功能的API接口函数
void derive02func()
{
cout << "call derive02func()::func" << endl;
}
};
我们的void show()应该区分判断一下,如果Base* p指向了其他的派生类对象,调用p->func()方法就好。但如果指向Derive2对象,不调用func()方法,而**** 这里就要识别*p的类型,看它指向哪个对象。此时就需要我们的dynamic_cast()了。dynamic会检查p指针是否指向的是一个Derive2类型的对象;p->vfptr->vftable
RTTI信息 如果是dynamic_cast,转换类型成功,返回Derive2对象地址;否则,返回nullptr。
void showFunc(Base* p)
{
//dynamic会检查p指针是否指向的是一个Derive2类型的对象
//p->vfptr->vftable RTTI信息 如果是dynamic_cast,
//转换类型成功,返回Derive2对象地址;否则,返回nullptr
Derive2 *pd2 = dynamic_cast<Derive2*>(p);
if (pd2 != nullptr)
{
pd2->derive02func();
}
else
{
p->func();//动态绑定
}
}
reinterpret_cast
类似于C风格的强制类型转换,是。
该运算符可以用来处理无关类型之间的转换,即用在任意指针(或引用)类型之间的转换,以及指针与足够大的整数类型之间的转换。由此可以看出,reinterpret_cast的效果很强大,但错误的使用reinterpret_cast很容易导致程序的不安全,只有将转换后的类型值转换回到其原始类型,这样才是正确使用reinterpret_cast方式。
int *p = nullptr;
double* b = reinterpret_cast<double*>(p);
课堂代码
#include <iostream>
using std::cout;
using std::endl;
void test()
{
int iNumber = 10;
float fNumber = 12.345;
/* iNumber = (int)fNumber; */
iNumber = int(fNumber);
}
void test2()
{
int iNumber = 10;
float fNumber = 12.345;
iNumber = static_cast<int>(fNumber);
cout << "inumber = " << iNumber << endl;
void *pret = malloc(sizeof(int));
int *pInt = static_cast<int *>(pret);
free(pInt);
pInt = nullptr;
}
void test3()
{
const int number = 100;
/* int *p1 = &number;//error */
int *p1 = const_cast<int *>(&number);
cout << "*p1 = " << *p1 << endl; //100
printf("p1's address : %p\n", p1);//0x7ffc1abeae5c
printf("number's address : %p\n", &number);//0x7ffc1abeae5c,地址相同(指向原对象)
//下面这个种行为C++已经不支持了,不要这样写,了解后不要纠结这里了
//地址相同,值不同
cout << endl;
*p1 = 200;//未定义行为
cout << "*p1 = " << *p1 << endl; //200
cout << "number = " << number << endl;//100
printf("p1's address : %p\n", p1); //0x7ffc1abeae5c
printf("number's address : %p\n", &number);//0x7ffc1abeae5c
}
int main(int argc, char **argv)
{
test3();
return 0;
}