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

类型转换

  • C语言类型转换:
    • (type)expression
    • expression(type)
#include 

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(expression)
const_cast
  • 一般用于去除const属性,将const转成非const;
#include 

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(p1);
    p2->m_age = 20;
    
    return 0;
}
dynamic_cast
  • 一般用于多态类型的转换,有运行时安全检测;
#include 

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(p1);//不安全的 无值NULL
    Student *s2 = dynamic_cast(p2);//安全的 有值
    
    return 0;
}
static_cast
  • 对比dynamic_cast,缺乏运行时安全检测;
  • 不能交叉转换,即类型完全不同的;
  • 常用于基本数据类型转换,非const转成const;
  • 使用范围广泛;
#include 

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(p1);//不安全  有值
    Student *s2 = static_cast(p2);//安全   有值
    
    Car *c1 = static_cast(p1); //报错 不能转换 类型不同
    int i = 10;
    double d = static_cast(i);
    
    return 0;
}
reinterpret_cast
  • 属于比较底层的强制类型转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据的拷贝;
  • 可交叉转换;
#include 

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(p1);//不安全  有值
    Student *s2 = reinterpret_cast(p2);//安全   有值
    
    Car *c1 = reinterpret_cast(p1); //不报错 能转换 类型不同 有值
    
    int i = 10;
    double d = reinterpret_cast(i);
    
    int *p = reinterp ret_cast(100);
    
    return 0;
}
新特性
  • auto:能自动推断出变量的类型;
  • decltype(a):获取变量a的数据类型;
  • nullptr:解决NULL的二义性问题,针对空指针的;
  • Lambda表达式:本质就是一个函数,相当于OC中block;
#include 

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 

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 

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 

using namespace::std;

class Person {
public:
    Person(){
        cout << "Person()" << endl;
    }
    ~Person(){
        cout << "~Person()" << endl;
    }
};

int main(int argc, const char * argv[]) {
    
    auto_ptr p(new Person());
    
    return 0;
}
  • 堆内存person对象,会自动释放,不用主动去调用delete函数了;
#include 

using namespace::std;

class Person {
public:
    Person(){
        cout << "Person()" << endl;
    }
    ~Person(){
        cout << "~Person()" << endl;
    }
};

int main(int argc, const char * argv[]) {
    
    shared_ptr p1(new Person());
    shared_ptr p2(p1);
    
    //shared_ptr指向数组
    auto expr = [](Person *p){
        delete [] p;
    };
    shared_ptr 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 p1(new Person());
    shared_ptr p2 = p1;
    shared_ptr p3= p1;
    shared_ptr p4 = p1;
    shared_ptr p5 = p1;
    
    cout << p1.use_count() << endl; //5
    
    return 0;
}
  • use_count可获取对象有多少个shared_ptr指针引用;

  • shared_ptr指针的循环引用

#include 

using namespace::std;

class Person;

class Car {
public:
//    Person *m_person;
    shared_ptr m_person = nullptr;
    Car(){
        cout << "Car()" << endl;
    }
    ~Car(){
        cout << "~Car()" << endl;
    }
};

class Person {
public:
//    Car *m_car;
    shared_ptr m_car = nullptr;
    Person(){
        cout << "Person()" << endl;
    }
    ~Person(){
        cout << "~Person()" << endl;
    }
};



int main(int argc, const char * argv[]) {
        
    //循环引用 内存泄漏
    shared_ptr person(new Person());
    shared_ptr car(new Car());
    
    person->m_car = car;
    car->m_person = person;
    
    return 0;
}
  • 解决方案:采用弱引用,如下所示:
class Car {
public:
//    Person *m_person;
//    shared_ptr m_person = nullptr;
    weak_ptr 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 p1(new Person());
    //p2指向堆对象 p1不再指向了
    unique_ptr p2 = std::move(p1);
    
    return 0;
}

你可能感兴趣的:(C++入门13 -- 类型转换,新特性,异常,智能指针)