首页 > 编程语言 >C++面向对象整理(9)之类型转换 dynamic_cast、static_cast、const_cast及其安全性

C++面向对象整理(9)之类型转换 dynamic_cast、static_cast、const_cast及其安全性

时间:2024-03-26 12:31:31浏览次数:37  
标签:类型转换 const dynamic cast 类型 转换 指针

C++面向对象整理(9)之C++的类型转换dynamic_cast、static_cast、const_cast

注:整理一些突然学到的C++知识,随时mark一下
例如:忘记的关键字用法,新关键字,新数据结构


C++ 的 类型转换


提示:本文为 C++ 中 类型转换 的写法和举例


一、C++的类型转换dynamic_cast、static_cast、const_cast

类型转换是非常重要的操作,它允许我们改变变量的类型。C++提供了四种类型转换操作符:static_cast、dynamic_cast、const_cast和reinterpret_cast。这些转换操作符在语法上相似,但它们在功能和使用场景上有所不同。

1、static_cast的静态类型转换

静态类型转换static_cast是最常用的一种类型转换操作符,它主要用于非多态类型的转换。它可以执行以下几种转换:

基本数据类型之间的转换:例如,将int转换为double,或将char转换为int。
非多态类的上下转型:这包括非多态类之间的转换以及父子类之间的指针或引用转换。但需要注意的是,这种转换在运行时并不检查类型的安全性,因此在使用时需要特别小心。
空指针和空类型的转换:例如,将nullptr转换为任意类型的指针或引用。
枚举和整数之间的转换

语法如下:

目标类型 转后变量 = static_cast<目标类型>(原变量);

2、 dynamic_cast的动态类型转换

动态类型转换dynamic_cast主要用于类继承的安全转换,特别是涉及多态的情况。它用于继承中指针或引用类型之间的转换
dynamic_cast还能用来侧向转换
dynamic_cast 运行时会类型检查,它依赖于虚函数表(vtable)和 RTTI(运行时类型识别)机制来实现。

子类型到父类型的转换(子转父):这种转换是安全的,并且总是成功。
父类型到子类型的转换(父转子):这种转换只有在运行时对象确实是目标类型时才成功
。如果转换失败,dynamic_cast会返回空指针(对于指针类型)或抛出异常(对于引用类型)。

语法如下:

目标类型 * variable = dynamic_cast<目标类型*>(原变量);
或者
目标类型 & variable = dynamic_cast<目标类型&>(原变量);

dynamic_cast在运行时进行类型检查,因此它比static_cast更安全,但性能开销也更大。

3、const_cast

const_cast用于修改类型的const或volatile属性。只允许指针或者引用间的转换,且通常用于去除指针或引用的const属性,以便能够修改原本被声明为const的数据。

语法如下:

目标类型* variable = const_cast<目标类型*>(原变量);
或者
目标类型& variable = const_cast<目标类型&>(原变量);

使用const_cast时需要非常小心,因为它允许你修改原本不应该被修改的数据,这可能导致未定义的行为。

4、reinterpret_cast

reinterpret_cast 是 C++ 中最强大但也最危险的转换操作符之一。它允许程序员执行低级别的、几乎不检查类型的转换。reinterpret_cast 通常用于硬件寻址、位操作和将指针转换为整数等底层编程任务。由于它几乎不进行任何类型检查,因此使用时必须非常小心,以防止出现未定义行为,基本不推荐使用这个。

二、类型转换举例

1、 static_cast

例子:基本数据类型之间的转换

double d = 3.14;  
int i = static_cast<int>(d); // 将double类型的d转换为int类型,i的值为3

例子:非多态类的上下转型

class Base {};  
class Derived : public Base {};  
  
Derived d;  
Base* b = static_cast<Base*>(&d); // 将Derived类型的指针转换为Base类型的指针

2、dynamic_cast

例子:子类型到父类型的转换,又称向下转换(子类型到父类型的转换,安全
向下转换是从基类指针或引用转换到派生类指针或引用。如果转换失败(即原指针或引用并不实际指向目标类型的对象),dynamic_cast 会返回空指针(对于指针类型)或抛出 std::bad_cast 异常(对于引用类型)。

class Base {  
public:  
    virtual ~Base() {} // 需要虚析构函数来启用 RTTI  
};  
  
class Derived : public Base {};  
  
int main() {  
    Base* basePtr = new Derived(); // 指向 Derived 对象的 Base 类型指针  
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // 安全转换  
    if (derivedPtr != nullptr) {  
        // 转换成功,derivedPtr 现在指向实际的 Derived 对象  
        delete derivedPtr; // 通过派生类指针释放内存  
    } else {  
        // 转换失败,不会执行到这里  
    }  
    return 0;  
}

例子:父类型到子类型的转换(父转子,不安全

Base* basePtr = new Derived(); // 假设basePtr实际上指向Derived对象  
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);  
if (derivedPtr != nullptr) {  
    // 转换成功,derivedPtr现在指向实际的Derived对象  
} else {  
    // 转换失败,basePtr不指向Derived对象  
}

侧向转换(兄弟类之间的转换)
侧向转换是在具有共同基类的两个派生类之间进行转换。这种转换同样依赖于 RTTI,并且同样会在运行时检查类型是否匹配。

class Base {  
public:  
    virtual ~Base() {} // 虚析构函数  
};  
  
class Derived1 : public Base {};  
class Derived2 : public Base {};  
  
int main() {  
    Base* basePtr = new Derived1(); // 指向 Derived1 对象的 Base 类型指针  
    Derived2* derived2Ptr = dynamic_cast<Derived2*>(basePtr); // 尝试侧向转换  
    if (derived2Ptr == nullptr) {  
        // 转换失败,basePtr 不指向 Derived2 对象  
    } else {  
        // 转换成功,但这种情况通常不会发生,除非有多重继承的复杂情况  
    }  
    delete basePtr; // 通过基类指针释放内存  
    return 0;  
}

注意事项
dynamic_cast 只能用于含有虚函数的类,即多态类
dynamic_cast 主要用于处理指针和引用类型。
对于指针类型的转换,如果转换失败,dynamic_cast 会返回空指针。
对于引用类型的转换,如果转换失败,会抛出 std::bad_cast 异常。
使用 dynamic_cast 时需要确保对象实际上是指向目标类型的,否则转换会失败。
dynamic_cast 在性能上比 static_cast 要慢一些,因为它涉及到运行时类型检查。

3、const_cast

例子:去除const属性

const int a = 10;  
int* p = const_cast<int*>(&a); // 去除const属性,但修改*p是未定义行为  
  
// 注意:尽管上面的代码可以编译通过,但尝试修改*p的值是危险的,并且可能导致运行时错误。

在真实编程中,应该尽量避免使用const_cast来修改const对象,因为这破坏了const的语义,并可能导致不可预见的错误。const_cast的正确使用场景通常是在你知道某个const对象实际上不需要const属性,并且你有理由这么做的情况下。

4、reinterpret_cast

reinterpret_cast及其不安全,不推荐使用重解释转换。

例子:指针与整数之间的转换

int x = 42;  
int* ptr = &x;  
  
// 将指针转换为整数  
intptr_t intPtrValue = reinterpret_cast<intptr_t>(ptr);  
  
// 将整数转换回指针  
int* ptrFromInt = reinterpret_cast<int*>(intPtrValue);  
  
// 注意:此时ptrFromInt指向的地址与ptr相同,但转换过程并未检查类型的匹配性

例子:不同类型指针之间的转换

float* floatPtr = new float(3.14f);  
char* charPtr = reinterpret_cast<char*>(floatPtr);  
// 此时charPtr指向floatPtr所指向的内存地址,但是解释内存内容的方式不同  
// 这样的转换通常用于底层内存操作,并且需要程序员完全了解所涉及的类型和数据布局

在实际编程中,应该尽量避免使用 reinterpret_cast,除非你非常清楚它的含义和潜在风险,并且没有其他更安全的转换方法可用。如果可能的话,应该优先使用 static_cast、dynamic_cast 和 const_cast,因为它们提供了更安全的类型转换机制。

总结

static_cast用于执行非多态类型的转换,包括基本内置数据类型之间的转换和类之间的转换。
dynamic_cast主要用于类继承体系中的安全转换,特别是在涉及多态的情况下,不能用于内置数据类。
const_cast用于修改类型(只能指针或者应用)的const或volatile属性。

标签:类型转换,const,dynamic,cast,类型,转换,指针
From: https://blog.csdn.net/ULTRAmanTAROACE/article/details/137041605

相关文章

  • C++的四种强制类型转换符,看了就懂
    运行时类型检查转换dynamic_cast用途及条件1、基类要有虚函数2、主要用于“安全地向下转型”解释1、为什么基类要有虚函数?答:dynamic_cast在运行时会进行类型检查,这种检查不是语法上的检查,而是真实情况地检查。如何检查?如果代码中使用了强制类型转换dynamic_cast,编译器会......
  • day03 java自动类型转换 和 强制类型转换
    自动类型转换定义将取值范围小的类型自动提升为取值范围大的类型。注意比较的不是所占内存大小,而是数据类型取值范围的大小,如int整数类型和float浮点类型所占内存数大小相同但是浮点数采用ieee754标准计数法表示范围更大,所以int可以变为float并且不损失精度。当把存储......
  • 空指针、野指针和const修饰指针的区别
    关键:空指针和野指针都不允许访问,否则会报错。空指针指向变量中内存编号为0的空间用途1.初始化指针变量,并且空指针指向的内存不能进行解引用intmain(){ //指针变量p指向内存地址编号为0的空间 int*p=NULL; //访问空指针报错 //内存编号0~255为系统占用内......
  • constant-current-diode
    导航(返回顶部)1.简介1.1内部结构1.2它是如何工作的1.3属性2.LED绝配?2.1应用LED案例!2.2恒流二极管测量注意事项3.恒流二极管产品统计3.1currentregulatingdiode3.2产品统计分析3.3主流产品3.4更多产品来源1.简介 1.1内部结构 1......
  • non constant or forward reference address expression for section .ARM.extab 错误
    编译时报错:FAILED:STM32F103RET6_Test001.elfcmd.exe/C"cd.&&D:\ProgramFiles\gcc-arm-none-eabi\bin\arm-none-eabi-gcc.exe-g-Wl,-gc-sections,--print-memory-usage,-Map=D:/ProjectCode/CLion/test/STM32F103RET6_Test001/cmake-build-debug-arm-......
  • bouncycastle
    把下载的安装包放在%JAVA_HOME%\jre\lib\ext目录下面修改配置文件%JAVA_HOME%\jre\lib\security\java.security,在末尾添加security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider;具体如下:导入jar包demo.java点击查看代码importorg.bouncycastle.j......
  • const [increaseBigCats, increaseSmallCats] = useCatStore( (state) => [state.incr
    const[increaseBigCats,increaseSmallCats]=useCatStore((state)=>[state.increaseBigCats,state.increaseSmallCats],shallow);这段代码是在使用zustand这个React状态管理库。zustand提供了一种简洁的方式来创建可复用的状态存储,并允许组件通过hoo......
  • JAVA高级面向对象二:多态下的类型转换问题
     packagecom.itheima.多态;publicclassTest{//多态好处publicstaticvoidmain(String[]args){////好处1:实现解耦合,右边对象可以随时切换,后续业务随即改变//Peoplep1=newTeacher();//p1.run();////好处2:可以使用父......
  • C++中const小结
    const修饰普通变量表示变量的值不能被改变。下面两条语句(第2行和第3行)表示的意思一致。inta;constintca=42;//intconstca=42;const修饰指针指向常量的指针不能改变其指对象的值。第5行代码是错误的。inta=42;constint*ip=&a;intconst*ipp=......
  • JAVA基本数据类型转换、关键字、转义字符
    基本数据类型转换自动类型转换:容量小的类型自动转换成容量大的数据类型byte,short,它们在计算时会转换int类型如果把int转换成float值,或者long转换成double值,不需要强制转换,但可能丢失精度publicclassMain{publicstaticvoidmain(String[]args){byteb......