C++语言级别提供的四种类型转换方式
const_cast : 去掉(指针或者引用)常量属性的一个类型转换
static_cast : 提供编译器认为安全的类型转换(没有任何联系的类型之间的转换就被否定了,就编译不通过)
reinterpret_cast : 类似于C风格的强制类型转换,谈不上什么安全
dynamic_cast : 主要用在继承结构中,可以支持RTTI类型识别的上下转换
const_cast
const_cast
底层是语言级别的强制类型转换,底层实际上和强制类型转换是一样的
#include<bits/stdc++.h>
using namespace std;
int main()
{
const int a = 10;
int *p1 = (int *)&a;
int *p2 = const_cast<int*>(&a);
return 0;
}
实际上我们可以通过查看底层汇编发现上面两个转换类型都是一致的.但是这两个强转const_cast
会对安全性做更高严格的要求,比如类型不匹配的强转就报错,我们可以看到下面这个强转就能够成功,但是const_cast
就会因为类型不匹配而报错.
#include<bits/stdc++.h>
using namespace std;
int main()
{
const int a = 10;
double *p1 = (double *)&a;
double *p2 = const_cast<double *>(&a);//会报错
return 0;
}
并且还需要注意的是const_cast
转换的类型必须是指针或者引用类型,下面这种也是错的
#include<bits/stdc++.h>
using namespace std;
int main()
{
const int a = 10;
int b = const_cast<int >(&a);
return 0;
}
static_cast
提供编译器认为安全的类型转换(没有任何联系的类型之间的转换就被否定了,就编译不通过)
下面这个就是可以的,int和char是有关联有联系的,所以转换没问题。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a = 10;
char b = static_cast<int>(a);
return 0;
}
下面这种就不行,int*
和 short*
是指向不同类型的指针,它们之间不能直接进行类型转换。这是因为 int*
是指向整数类型的指针,而 short*
是指向短整数类型的指针,它们指向的数据类型不同。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int *p = nullptr;
short *q = static_cast<short *>(p);
return 0;
}
static_cast
也提供类之间的转化,但指提供有联系的类之间的转化,并且转化不保证安全,需要写代码的人来保证转化的合理性
#include<bits/stdc++.h>
using namespace std;
int main() {
class Base {
// ...
};
class Derived : public Base {
// ...
};
Base* basePtr = new Derived;
Derived* derivedPtr = static_cast<Derived*>(basePtr); // 将基类指针转换为派生类指针
return 0;
}
dynamic_cast
dynamic_cast
是 C++ 中的一种类型转换操作符,用于在运行时进行类型转换。它主要用于在继承层次结构中进行向下转型(downcasting),即将基类的指针或引用转换为派生类的指针或引用。与 static_cast
不同,dynamic_cast
在转换时会进行运行时类型检查,以确保转换的安全性。
dynamic_cast
的底层原理涉及到 C++ 的运行时类型信息(RTTI)。在对象的内存布局中,通常会有一个指向虚函数表(vtable)的指针,虚函数表中存储了每个虚函数的地址。dynamic_cast
利用这个虚函数表来进行运行时类型检查。
具体来说,当使用 dynamic_cast
进行类型转换时,它会首先检查指针或引用指向的对象的实际类型。它会在对象的内存中查找类型信息,这个信息通常存储在虚函数表中。然后,它会比较目标类型和实际类型,如果目标类型是实际类型的基类或者派生类,那么转换就是合法的,否则转换会失败。
需要注意的是,dynamic_cast
只能用于具有虚函数的类层次结构中,因为只有具有虚函数的类才会有虚函数表,从而可以进行运行时类型检查。此外,dynamic_cast
只能用于指针和引用的类型转换,不能用于基本类型的转换。
总的来说,dynamic_cast
提供了一种安全的、运行时的类型转换方式,通过运行时类型信息来确保转换的安全性。这使得在面对复杂的继承层次结构时,能够更加方便地进行类型转换,并且避免了潜在的类型转换错误。
#include<bits/stdc++.h>
using namespace std;
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; }
//Derive2实现新功能的API接口函数
void derive02func()
{
cout << "call Derive2::derive02func" << endl;
}
};
/*
typeid(*p).name() == "Derive"
*/
void showFunc(Base *p)
{
//dynamic_cast会检查p指针是否指向的是一个Derive2类型的对象?
//通过p访问->vfptr访问->vftable RTTI信息 如果是,dynamic_cast转换类型成功,
//返回Derive2对象的地址,给pd2;否则返回nullptr
//static_cast是编译时期的类型转换 dynamic_cast是运行时期的类型转换,是支持RTTI信息识别的
Derive2 *pd2 = dynamic_cast<Derive2*>(p);
if (pd2 != nullptr)
{
pd2->derive02func();
}
else
{
p->func();//动态绑定 *p的类型 Derive2 derive02func
}
}
int main()
{
Derive1 d1;
Derive2 d2;
showFunc(&d1);
showFunc(&d2);
return 0;
}
call Derive1::func
call Derive2::derive02func
作为对比,我们可以看到如果把dynamic_cast
改成static_cast
,这个转换结果会始终成功
call Derive2::derive02func
call Derive2::derive02func
reinterpret_cast
reinterpret_cast
是 C++ 中的一种类型转换操作符,用于执行低级别的类型转换,可以将一个指针或引用转换为另一种类型的指针或引用,即使这两种类型之间没有直接的关联也可以进行转换。reinterpret_cast
允许进行各种不安全的转换,包括将整数转换为指针,指针转换为整数,以及将指针类型转换为不同类型的指针,而不进行任何类型检查。
所以reinterpret_cast
是相对来说最不安全的转换
int main() {
int x = 10;
// 将整数转换为指针
int* ptr = reinterpret_cast<int*>(&x);
// 将指针转换为整数
uintptr_t address = reinterpret_cast<uintptr_t>(ptr);
// 将指针类型转换为不同类型的指针
struct MyStruct {
int a;
double b;
};
MyStruct* structPtr = reinterpret_cast<MyStruct*>(ptr);
return 0;
}