美文网首页
015-类型转换和C++11新特性

015-类型转换和C++11新特性

作者: 一亩三分甜 | 来源:发表于2021-10-06 18:29 被阅读0次

    《C++文章汇总》
    上一篇介绍了《014-模板、自定义动态数组》,本文介绍类型转换。

    1.类型转换

    ◼ C语言风格的类型转换符

    (type)expression
    type(expression)

    int main(){ 
        int a = 10;
        double d = static_cast<double>(a);
        //隐式转换
    //    double d = a;
        //显式转换
    //    double d = (double) a;
    //    double e = double(a);
        
        getchar();
        return 0;
    }
    

    ◼ C++中有4个类型转换符

    static_cast
    dynamic_cast
    reinterpret_cast
    const_cast
    使用格式:xx_cast<type>(expression)

    I.const_cast

    ◼ 一般用于去除const属性,将const转换成非const
    两种写法,汇编代码一样

    const Person *p1 = new Person();
    Person *p2 = const_cast<Person *>(p1);
    Person *p3 = (Person *)p1;
    

    II.dynamic_cast

    ◼ 一般用于多态类型的转换,有运行时安全检测
    明显看到不安全的指针指向p1赋值给stu1没有赋值成功,stu1为0x0空指针NULL,dynamic_cast进行了安全检测,p2则成功赋值给了stu2

    class Person{
        int m_age;
        virtual void run(){};
    };
    class Student:public Person{
        
    };
    int main(){
        
        Person *p1 = new Person();
        Person *p2 = new Student();
        cout << "p1 = " << p1 << endl;
        cout << "p2 = " << p2 << endl;
        //原始做法
    //    Student *stu1 = (Student *)p1;
    //    Student *stu2 = (Student *)p2;
        Student *stu1 = dynamic_cast<Student *>(p1);//不安全,子类指针指向父类对象
        Student *stu2 = dynamic_cast<Student *>(p2);//安全
        cout << "stu1=" << stu1 << endl;
        cout << "stu1=" << stu2 << endl;
    }
    //输出
    p1 = 0x100658690
    p2 = 0x100659bb0
    stu1=0x0
    stu1=0x100659bb0
    

    原始赋值方式不会做安全检测,直接赋值过去,并不会将指针置为0x00000000(NULL)

    //原始做法
    //    Student *stu1 = (Student *)p1;
    //    Student *stu2 = (Student *)p2;
    

    Car对象和Person对象一点联系也没有,赋值会做安全检测置为NULL

    class Car{
        int m_age;
        int m_price;
        int m_height;
    };
    int main(){
        Person *p1 = new Person();
        Person *p2 = new Student();
        cout << "p1 = " << p1 << endl;
        cout << "p2 = " << p2 << endl;
        Car *c1 = (Car *)p1;
        Car *c2 = dynamic_cast<Car *>(p2);
        cout << "c1 = " << c1 << endl;
        cout << "c2 = " << c2 << endl;
    }
    //输出
    p1 = 0x1005aa3d0
    p2 = 0x1005a8980
    c1 = 0x1005aa3d0
    c2 = 0x0
    

    III.static_cast

    ◼ 对比dynamic_cast,缺乏运行时安全检测
    ◼ 不能交叉转换(不是同一继承体系的,无法转换)


    图片.png

    ◼ 常用于基本数据类型的转换、非const转成const

    int a = 10;
    double b = static_cast<int>(a);
    
    Person *p1 = new Person();
    const Person *p2 = static_cast<const Person *>(p1);//相当于const Person *p2 = p1;不写转换也会自动转
    

    ◼ 使用范围较广,大多数转换都能适用

    IV.reinterpret_cast

    ◼ 属于比较底层的强制转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据拷贝
    ◼ 可以交叉转换
    ◼ 可以将指针和整数互相转换

    int main(){
    //小端模式0A 00 00 00/0000 1010 0000 0000 0000 0000 0000 0000
    int a = 10;
    //0A 00 00 00 00 00 00 00理想情况
    //00 00 00 00 00 00 24 40实际情况,浮点数据的存储和整形数据的存储是不一样的,寄存器的使用不同
    double d = a;
    //理想情况下汇编代码
    //mov eax,dword ptr [a]
    //mov dword ptr [d], eax
    /**实际情况
     汇编代码如下,并不是简简单单的二进制拷贝
     xmm0,mmword ptr [__real@4024000000000000 (0979CA0h)]
     mmword ptr [d],xmm0
     */
    cout << "a = " << a << endl;
    cout << "d = " << d << endl;
    }
    //输出
    a = 10
    d = 10
    

    仅仅只单独的进行二进制拷贝,a的值拷贝到d中,则使用reinterpret_cast,最后得出的值d就不确定了d = 4.94066e-323

    int main(){
         int a = 10;
         double d = reinterpret_cast<double&>(a);
    //汇编代码如下
    /**
     movsd xmm0,mmword ptr [a]
     movsd mmword ptr [d],xmm0
     二进制拷贝完成后d中内存空间为
     0A 00 00 00 cc cc cc cc
     */
         cout << "a = " << a << endl;
         cout << "d = " << d << endl;
    }
    //输出
    a = 10
    d = 4.94066e-323
    

    小数的存储格式,8.25-->1000.01-->1.00001*2^3(3是指数,00001是尾数)


    图片.png
    int *p = reinterpret_cast<int *>(0x100);
    int b = reinterpret_cast<int>(p);
    

    int数据拷贝给double类型要写引用,int *直接给int不用写引用

    int *p = reinterpret_cast<int *>(0x100);
    int b = reinterpret_cast<int>(p);
    //无需写成引用
    int a = 10;
    double d = reinterpret_cast<double&>(a);
    

    2.C++11新特性

    ◼ auto

    可以从初始化表达式中推断出变量的类型,大大简化编程工作

    class Person{
    public:
        void run(){
            
        };
    };
    int main(){
        
        auto a = 10;//int
        auto str = "c++";//const char *
        auto p = new Person();//Person *
        p->run();
    }
    

    属于编译器特性,不影响最终的机器码质量,不影响运行效率

    ◼ decltype

    可以获取变量的类型

    int b = 10;
    decltype(b) c = 20;//int
    

    ◼ nullptr

    可以解决NULL的二义性问题
    c++98,NULL宏定义为0,产生了二义性,两个函数都满足调用条件


    图片.png
    void func(int v){
        cout << "void func(int v)" << v << endl;
    }
    void func(int *v){
        cout << "void func(int *v)" << v << endl;
    }
    int main(){
        int m = NULL;
        int *n = NULL;
    }
    

    c++11开始NULL为整数0,空指针用nullptr

    void func(int v){
        cout << "void func(int v)" << v << endl;
    }
    void func(int *v){
        cout << "void func(int *v)" << v << endl;
    }
    int main(){
        int m = NULL;
        int *n = nullptr;
        int *q = new int;
        delete q;
        q = nullptr;
        func(NULL);
        func(nullptr);
    }
    //输出
    void func(int v) - 0
    void func(int *v) - 00000000
    

    ◼ 快速遍历

    int array[] = {10,20,30,40,50};
    for(int item:array){
        cout << item << endl;
    }
    //输出
    10
    20
    30
    40
    50
    

    更加简洁的初始化方式

    int array0[] {10,20,30,40,50};//等价于int array[] = {10,20,30,40,50};
    

    相关文章

      网友评论

          本文标题:015-类型转换和C++11新特性

          本文链接:https://www.haomeiwen.com/subject/tpuonltx.html