首页 > 编程语言 >C++四种强制类型详解

C++四种强制类型详解

时间:2023-05-31 13:22:57浏览次数:43  
标签:转换 int 派生类 C++ cast 详解 基类 四种 指针

向上转型(上行转换)

  • 派生类对象转换为基类对象(包括指针和对象),直接转换由编译器完成,是绝对安全的
  • 内存里面:基类对象相当于只是换了个地址,换成了派生类中存储基类成员的内存地址,但是派生类对象中有的,基类没有的变量仍然存在内存中(保留了再次从基类转换成派生类的可能性)

向下转型(下行转换)

  • 向下转型是将基类指针或引用转换回派生类指针或引用的操作,但是向下转型是一种不安全的操作,因为基类指针或引用可能指向的并不是派生类对象,因此在进行向下转型之前,最好使用dynamic_cast进行类型检查,以确保安全转换
#include <iostream>
using namespace std;

class Base {
public:
    virtual ~Base() {} // 基类声明虚析构函数,以便正确释放内存
};

class Derived : public Base {
public:
    void anotherFunction() {
        // 实现派生类的一些功能
    }
};

int main() {
    Base* basePtr = new Base(); // 创建派生类对象,并用基类指针指向它

    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // 向下转型

    if (derivedPtr) {//如果不是派生类转换而来的basePtr,再转换会Derived会返回一个NULL
        derivedPtr->anotherFunction(); // 可以访问派生类的成员函数
    }


    delete basePtr; // 删除动态分配的对象

    return 0;
}

四种强制类型转换

  • C++支持C风格的强制转换,但是C风格的强制转换可能带来一些隐患,所以C++提供了一组适用于不同场景的强制转换的函数
    static_cast
  • 用处:
    • 用于类层次结构中基类和派生类之间指针或引用的转换
      • 上行转换是安全的
      • 进行下行转换,由于没有动态类型检查,所以是不安全的
    • 用于基类数据类型之间的转换,例如把int转换成char,这种转换的安全也要开发人员保证
    • 把空指针转换成目标类型的空指针
    • 把任何类型的表达式转换成void类型
double x = 1.2;
int y = static_cast<int>(x);//会损失一部分精度
cout<<y<<endl;

int x1 = -1;
unsigned int x2 = static_cast<unsigned int>(x1);
cout<<x1<<" "<<x2<<endl;//-1 4294967295因为无符号和有符号的表示方法不同,所以显示的结果也不同

//A是基类,B是派生类
A* a2 = new B(1,2);
B* b2 = static_cast<B*>(a2);//安全的

A* a3 = new A(1);
B* b3 = static_cast<B*>(a3);//不安全的

void *v1 = nullptr;
A* a4 = static_cast<A*>(v1);
void *v2 = static_cast<void *>(a4);

dynamic_cast

  • 其他三种都是编译时完成,dynamic_cast是运行时处理,运行时要进行类型检查
  • 注意
    • 不能用于内置的基本数据类型的强制转换
    • 使用dynamic_cast进行转换时,基类中一定要有虚函数,否则编译不通过。这是因为运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表
  • 用处:主要用于类之间的转换
    • 上行转换时,dynamic_cast和static_cast的效果是一样的,但是一般使用static_cast
    • 下行转换时,dynamic_cast具有类型检查,比static_cast更安全,向下转换成功与否与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同(或者要转换的是实际的父类),否则转换失败
  • dynamic_cast要求<>所描述的目标类型必须为指针或引用,转换成功的返回指向类的指针或引用
    • 失败,指针返回空指针
    • 引用会抛出一个bad_cast的异常
    • 所以如果是指针需要进行是否为空的判断,引用需要try catch一下
class A{
public:
    int a;
    A(int a):a(a){}
    virtual ~A(){}
};

class B:public A{
public:
    int b;
    B(int a,int b):A(a),b(b){};
};

class C:public B{
public:
    int c;
    C(int a,int b,int c):B(a,b),c(c){}
};


int main(){
    A* a2 = new C(1,2,3);
    B* b2 = dynamic_cast<B*>(a2);
    if(b2== nullptr) cout<<"qwe";
    else cout<<"asd";
}

const_cast

  • <>里的类型也只能是指针或引用
  • 去除const属性
    • 当我们有一个指向const对象的指针或引用时,如果确保不会修改该对象的值,但需要将其传递给一个接收非const对象的函数或方法时,可以使用const_cast去除const属性,这样做是为了允许调用这个函数,但是如果实际上对该对象进行了修改,将导致未定义行为
const int num = 10;
int &num1 = const_cast<int&>(num);
  • 转换掉volatile属性
volatile int num = 10;
int& num1 = const_cast<int&>(num);

reinterpret_cast

  • 改变指针或引用的类型
  • 将指针或引用转换为一个足够长度的整型 long long int,或者uint_64等等
  • 将整型转换为指针或引用类型
int num = 0x00636261;
int *pNum  = &num;
char* pStr = reinterpret_cast<char*>(pNum);
cout<<pStr<<endl;//abc 
  • 一个指向字符串的指针和一个指向整型的指针没有什么不同(内存角度),实际输出的不同是指针类型会教导编译器如何解释某个特定地址中的内存内容及其大小

标签:转换,int,派生类,C++,cast,详解,基类,四种,指针
From: https://www.cnblogs.com/sunjianzhao/p/17445814.html

相关文章

  • C/C++杂记:运行时类型识别(RTTI)与动态类型转换原理
    运行时类型识别(RTTI)的引入有三个作用:配合typeid操作符的实现;实现异常处理中catch的匹配过程;实现动态类型转换dynamic_cast。1.typeid操作符的实现1.1.静态类型的情形C++中支持使用typeid关键字获取对象类型信息,它的返回值类型是conststd::type_info&,例:#include<type......
  • C/C++杂记:虚函数的实现的基本原理
    1.概述简单地说,每一个含有虚函数(无论是其本身的,还是继承而来的)的类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数对应的函数指针。例:其中:B的虚函数表中存放着B::foo和B::bar两个函数指针。D的虚函数表中存放的既有继承自B的虚函数B::foo,又有重写(override)了基......
  • C/C++杂记:深入理解数据成员指针、函数成员指针
    1.数据成员指针对于普通指针变量来说,其值是它所指向的地址,0表示空指针。而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始地址的偏移值,空指针用-1表示。例:代码示例:structX{inta;intb;};#defineVALUE_OF_PTR(p)(*(long*)&p)int......
  • 【C++】c++单继承、多继承、菱形继承内存布局(虚函数表结构)
    单继承:只有一个基类和一个派生类classBase{public:virtualvoidfun1(){cout<<"Base::func1()"<<endl;}virtualvoidfun2(){cout<<"Base::func2()"<<endl;}private:intb;......
  • C++ 在函数内部输出当前类名方式
    开发环境:QtCreator C++1usingnamespacestd;23/*基类汽车*/4classCar5{6public:7Car(){}8virtual~Car(){}9virtualvoidmove(void);10};1112/*基本属性汽车运动*/13voidCar::move(void)14{15cout<<......
  • C++多态虚函数表详解(多重继承、多继承情况)
    本文关键词:C++多态多继承多重继承虚函数表虚函数指针动态绑定概述:C++相对其他面向对象语言来说,之所以灵活、高效。很大程度的占比在于其多态技术和模板技术。C++虚函数表是支撑C++多态的重要技术,它是C++动态绑定技术的核心。本文章将着重图解虚函数表相关知识,在阅读本文......
  • 10.UG钣金使用方法详解
    1.创建钣金件或者拉伸后转换为钣金2.    ......
  • BIO、NIO、AIO区别详解
    BIO:同步阻塞主线程发起io请求后,需要等待当前io操作完成,才能继续执行。NIO:同步非阻塞引入selector、channel、等概念,当主线程发起io请求后,轮询的查看系统是否准备好执行io操作,没有准备好则主线程不会阻塞会继续执行,准备好主线程会阻塞等待io操作完成。AIO:异步非阻塞主线程发起......
  • redis 7.0 配置文件详解
    本文配置文件版本是Redis7.0。5.5.1常规通用配置这些是我的常规配置,每个Redis启动必备参数,你一定要掌握,涉及到网络、模块插件、运行模式、日志等。MODULES这个配置可以加载模块插件增强我的功能,常见的模块有RedisSearch、RedisBloom等。关于模块加载可以参考【5.6布隆......
  • c++中的析构函数和纯虚函数
    析构函数:c++中当delete一个类对象时,会默认调用其析构函数,析构函数的作用就是释放对象占用的堆空间。一般基类的析构函数需写成虚函数,这是因为在多态下,我们一般用基类的指针来指向一个子类对象,若基类的虚函数未被重写,那么可能会造成内存泄漏。因此需要在子类重写基类的虚函数来......