美文网首页
C++入门13 -- 类型转换,新特性,异常,智能指针

C++入门13 -- 类型转换,新特性,异常,智能指针

作者: YanZi_33 | 来源:发表于2021-08-18 12:28 被阅读0次

    类型转换

    • C语言类型转换:
      • (type)expression
      • expression(type)
    #include <iostream>
    
    using namespace::std;
    
    int main(int argc, const char * argv[]) {
        
        int a = 10;
        double d1 = (double)a;
        double d2 = double(a);
        
        return 0;
    }
    
    • C++语言类型转换:
      • xx_cast<type>(expression)
    const_cast
    • 一般用于去除const属性,将const转成非const;
    #include <iostream>
    
    using namespace::std;
    
    class Person {
    public:
        int m_age;
    };
    
    int main(int argc, const char * argv[]) {
    
        //不可修改
        const Person *p1 = new Person();
        
        //const_cast 变成可修改
        Person *p2 = const_cast<Person *>(p1);
        p2->m_age = 20;
        
        return 0;
    }
    
    dynamic_cast
    • 一般用于多态类型的转换,有运行时安全检测;
    #include <iostream>
    
    using namespace::std;
    
    class Person {
    public:
        int m_age;
        virtual void run(){};
    };
    
    class Student : public Person{
    public:
        int m_score;
    };
    
    int main(int argc, const char * argv[]) {
    
        Person *p1 = new Person();
        Person *p2 = new Student();
        
        Student *s1 = dynamic_cast<Student *>(p1);//不安全的 无值NULL
        Student *s2 = dynamic_cast<Student *>(p2);//安全的 有值
        
        return 0;
    }
    
    static_cast
    • 对比dynamic_cast,缺乏运行时安全检测;
    • 不能交叉转换,即类型完全不同的;
    • 常用于基本数据类型转换,非const转成const;
    • 使用范围广泛;
    #include <iostream>
    
    using namespace::std;
    
    class Person {
    public:
        int m_age;
        virtual void run(){};
    };
    
    class Student : public Person{
    public:
        int m_score;
    };
    
    class Car {
    public:
        
    };
    
    int main(int argc, const char * argv[]) {
    
        Person *p1 = new Person();
        Person *p2 = new Student();
        
        Student *s1 = static_cast<Student *>(p1);//不安全  有值
        Student *s2 = static_cast<Student *>(p2);//安全   有值
        
        Car *c1 = static_cast<Car *>(p1); //报错 不能转换 类型不同
        int i = 10;
        double d = static_cast<double>(i);
        
        return 0;
    }
    
    reinterpret_cast
    • 属于比较底层的强制类型转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据的拷贝;
    • 可交叉转换;
    #include <iostream>
    
    using namespace::std;
    
    class Person {
    public:
        int m_age;
        virtual void run(){};
    };
    
    class Student : public Person{
    public:
        int m_score;
    };
    
    class Car {
    public:
        
    };
    
    int main(int argc, const char * argv[]) {
    
        Person *p1 = new Person();
        Person *p2 = new Student();
        
        Student *s1 = reinterpret_cast<Student *>(p1);//不安全  有值
        Student *s2 = reinterpret_cast<Student *>(p2);//安全   有值
        
        Car *c1 = reinterpret_cast<Car *>(p1); //不报错 能转换 类型不同 有值
        
        int i = 10;
        double d = reinterpret_cast<double &>(i);
        
        int *p = reinterp ret_cast<int *>(100);
        
        return 0;
    }
    
    新特性
    • auto:能自动推断出变量的类型;
    • decltype(a):获取变量a的数据类型;
    • nullptr:解决NULL的二义性问题,针对空指针的;
    • Lambda表达式:本质就是一个函数,相当于OC中block;
    #include <iostream>
    
    using namespace::std;
    
    int main(int argc, const char * argv[]) {
    
        //本质是一个函数
        int (*p)(int,int) = [](int a,int b) -> int {
            return a + b;
        };
        
        cout << p(10,20) << endl;
        
        return 0;
    }
    
    int main(int argc, const char * argv[]) {
        
        int a = 10;
        int b = 20;
        
        //默认是值捕获
        auto p = [a,b] {
            cout << a << endl;
            cout << b << endl;
        };
        
        //地址,引用捕获
        auto p1 = [&a,&b] {
            cout << a << endl;
            cout << b << endl;
        };
        
        
        a = 11;
        b = 22;
        
        p();
        p1();
        
        return 0;
    }
    
    • auto类型推断,直接接收Lambda表达式;
    int main(int argc, const char * argv[]) {
    
        int a = 10;
        int b = 20;
        
        //默认是值捕获
        auto p = [a,b] () mutable {
            a++;
            b++;
            cout << a << endl; //11
            cout << b << endl; //21
        };
        
        p();
        
        cout << a << endl; //10
        cout << b << endl; //20
        
        return 0;
    }
    
    • mutable ,可修改值捕获的变量值;

    错误

    • 变成过程中常见的错误类型:
      • 语法错误;
      • 逻辑错误;
      • 异常;

    异常

    • 异常是一种发生在程序运行过程中发生的不好预测的错误,比如内存不足;
    • 异常没有被处理,会导致程序闪退;
    • throw抛出异常之后,会在当前函数查找匹配的catch,找不到就中止当前的函数代码,去上一层函数中查找,若最终都找不到匹配的catch,就会导致程序崩溃退出;
    int main(int argc, const char * argv[]) {
        
     try {
         //内存溢出
         for (int i = 0; i < 99999999; i++) {
             int *p = new int[99999999];
         }
     } catch (...) {//捕获到异常
         cout << "发生了异常" << endl;
     }
        
        return 0;
    }
    
    • 以上是系统抛出的异常;
    • catch (...)拦截所有异常;
    #include <iostream>
    
    using namespace::std;
    
    int divide(int a,int b){
        //抛出异常 值为100 或者 "除数不能为0"
    //    if (b == 0) throw 100;
        if (b == 0) throw "除数不能为0";
    
        return a / b;
    }
    
    int main(int argc, const char * argv[]) {
        
        try {
            int m = 100;
            int n = 0;
            cout << divide(m, n) << endl;
        } catch (int exception) {
            cout << "捕获到异常: " << exception << endl;
        } catch (const char *str) {
            cout << "捕获到异常: " << str << endl;
        }
    
        return 0;
    }
    
    • throw抛出异常,catch捕获处理异常;

    智能指针

    • 传统指针存在的问题:
      • 需要手动管理内存;
      • 容易发生内存泄漏;
      • 释放之后变成野指针;
    #include <iostream>
    
    using namespace::std;
    
    void test(){
        throw 6;
    }
    
    int main(int argc, const char * argv[]) {
        
        //异常导致内存泄漏
        try {
            int *p = new int();
            test();
            delete p;
        } catch (...) {
            cout << "发生异常" << endl;
        }
        
        return 0;
    }
    
    • 智能指针可解决传统指针存在的问题:
      • auto_ptr:不推荐使用,存在缺陷不能指向数组;
      • shared_ptr:属于C++11标准;
      • unique_ptr:属于C++11标准;
    #include <iostream>
    
    using namespace::std;
    
    class Person {
    public:
        Person(){
            cout << "Person()" << endl;
        }
        ~Person(){
            cout << "~Person()" << endl;
        }
    };
    
    int main(int argc, const char * argv[]) {
        
        auto_ptr<Person> p(new Person());
        
        return 0;
    }
    
    • 堆内存person对象,会自动释放,不用主动去调用delete函数了;
    #include <iostream>
    
    using namespace::std;
    
    class Person {
    public:
        Person(){
            cout << "Person()" << endl;
        }
        ~Person(){
            cout << "~Person()" << endl;
        }
    };
    
    int main(int argc, const char * argv[]) {
        
        shared_ptr<Person> p1(new Person());
        shared_ptr<Person> p2(p1);
        
        //shared_ptr指向数组
        auto expr = [](Person *p){
            delete [] p;
        };
        shared_ptr<Person> p3(new Person[5]{},expr);
    
        return 0;
    }
    
    • 多个shared_ptr指针可以指向同一个对象,当最后一个shared_ptr指针销毁时,指向的堆对象才会被销毁;
    • shared_ptr指向数组时,传入lambad表达式,释放所有堆对象;
    • shared_ptr指针的原理与OC中的strong相似,强引用;
    • 一个shared_ptr指针会对对象产生一个强引用,引用计数+1;
    int main(int argc, const char * argv[]) {
        
        shared_ptr<Person> p1(new Person());
        shared_ptr<Person> p2 = p1;
        shared_ptr<Person> p3= p1;
        shared_ptr<Person> p4 = p1;
        shared_ptr<Person> p5 = p1;
        
        cout << p1.use_count() << endl; //5
        
        return 0;
    }
    
    • use_count可获取对象有多少个shared_ptr指针引用;

    • shared_ptr指针的循环引用

    #include <iostream>
    
    using namespace::std;
    
    class Person;
    
    class Car {
    public:
    //    Person *m_person;
        shared_ptr<Person> m_person = nullptr;
        Car(){
            cout << "Car()" << endl;
        }
        ~Car(){
            cout << "~Car()" << endl;
        }
    };
    
    class Person {
    public:
    //    Car *m_car;
        shared_ptr<Car> m_car = nullptr;
        Person(){
            cout << "Person()" << endl;
        }
        ~Person(){
            cout << "~Person()" << endl;
        }
    };
    
    
    
    int main(int argc, const char * argv[]) {
            
        //循环引用 内存泄漏
        shared_ptr<Person> person(new Person());
        shared_ptr<Car> car(new Car());
        
        person->m_car = car;
        car->m_person = person;
        
        return 0;
    }
    
    • 解决方案:采用弱引用,如下所示:
    class Car {
    public:
    //    Person *m_person;
    //    shared_ptr<Person> m_person = nullptr;
        weak_ptr<Person> m_person;
        Car(){
            cout << "Car()" << endl;
        }
        ~Car(){
            cout << "~Car()" << endl;
        }
    };
    
    • weak_ptr是弱引用;

    • unique_ptr也会对对象产生一个强引用,但同一时间只能有一个unique_ptr指针指向堆对象;

    • 引用权限转移:调用std::move函数;

    int main(int argc, const char * argv[]) {
        
        //unique_ptr
        unique_ptr<Person> p1(new Person());
        //p2指向堆对象 p1不再指向了
        unique_ptr<Person> p2 = std::move(p1);
        
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:C++入门13 -- 类型转换,新特性,异常,智能指针

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