C++ 快速回顾(六)
前言
用于快速回顾之前遗漏或者补充C++知识
一、const_cast
const_cast主要用于添加或移除const(或volatile)属性。它不改变类型本身,只改变类型的常量性。注意:移除常量性的操作必须谨慎,因为修改一个原本定义为常量的对象会导致未定义行为。
如下是正常的转换:
class FTestClass
{
public:
void Init() {
}
};
int main()
{
const FTestClass* Ptr = new FTestClass();
//Ptr->Init();
FTestClass* NotConstPtr1 = const_cast<FTestClass*>(Ptr);
NotConstPtr1->Init();
FTestClass* NotConstPtr2 = (FTestClass*)Ptr;
NotConstPtr2->Init();
system("pause");
return 0;
}
如下是错误的转换
const int a = 10;
int* aa = const_cast<int*>(&a);
*aa = 20; // 错误!!! 无法修改
std::cout << a; // 这里还是10
二、reinterpret_cast
reinterpret_cast提供低层次的重新解释位模式的转换。它可以将任意指针类型转换为另一个指针类型,或者将指针和整数之间转换。这种转换非常不安全,因为它不进行任何类型检查。通常用于底层编程,如驱动程序和需要直接操作内存的场合。
int main()
{
FTestClass* Ptr = new FTestClass();
// 转换为int值 再 转换回去
int value = reinterpret_cast<int>(Ptr);
FTestClass* NewValue1 = reinterpret_cast<FTestClass*>(value);
NewValue1->Init();
// 转换为int指针 再 转换回去
int* IntPtr = reinterpret_cast<int*>(Ptr);
FTestClass* NewValue2 = reinterpret_cast<FTestClass*>(IntPtr);
NewValue2->Init();
system("pause");
return 0;
}
三、dynamic_cast
dynamic_cast主要用于在类层次结构中进行安全的向下转换(即基类指针或引用转换为派生类)以及跨继承转换(如多继承中的兄弟类之间的转换)。它需要运行时类型信息(RTTI)支持,因此只能用于多态类型(即类至少有一个虚函数)。如果转换失败,对于指针转换返回nullptr,对于引用转换则抛出std::bad_cast异常。
注意:dynamic_cast 是安全的转换,当转换失败时会返回空指针,并不会变成野指针
class FTestClass
{
public:
void BaseFunc()
{
}
//dynamic_cast 必须有虚函数才能转换
virtual void Init()
{
}
};
class FTestChildClass : public FTestClass
{
public:
void ChildFunc()
{
}
};
int main()
{
FTestClass* Ptr = new FTestChildClass();
FTestChildClass* ChildPtr = dynamic_cast<FTestChildClass*>(Ptr);
ChildPtr->BaseFunc();
ChildPtr->ChildFunc();
FTestClass* Ptr1 = new FTestClass();
FTestChildClass* ChildPtr1 = dynamic_cast<FTestChildClass*>(Ptr1);
if (ChildPtr1 == nullptr)
{
printf("is null.\r\n");
}
system("pause");
return 0;
}
四、static_cast
static_cast是最常用的转换,用于非多态类型的转换。它可以在相关类型之间进行转换,比如整数到浮点数,或者指针在类层次结构中的向上转换(即基类指针指向派生类对象,这是安全的)。它也可以用于任何隐式转换的逆转换(例如,将void*转换为其他指针类型,或者将基类指针转换为派生类指针,但后者是不安全的,需要程序员确保安全)
class FTestClass
{
public:
void BaseFunc()
{
printf("Base\r\n");
}
};
class FTestChildClass : public FTestClass
{
public:
void ChildFunc()
{
printf("Child\r\n");
printf("%d\r\n", a);
}
int a = 10;
};
int main()
{
FTestClass* Ptr = new FTestChildClass();
FTestChildClass* ChildPtr = static_cast<FTestChildClass*>(Ptr);
ChildPtr->BaseFunc();
ChildPtr->ChildFunc();
FTestClass* Ptr1 = new FTestClass();
FTestChildClass* ChildPtr1 = static_cast<FTestChildClass*>(Ptr1); // 转换失败不会为空,会变成野指针
ChildPtr1->BaseFunc();
//这里的函数理论上转换失败为什么还能调用?
// 是因为函数是在编译时就确定好了,但是如果访问其中的变量值就会出现问题
ChildPtr1->ChildFunc();
system("pause");
return 0;
}