JHHK

欢迎来到我的个人网站
行者常至 为者常成

16、类型转换、C++新特性

目录

类型转换

C语言风格的类型转换符
(type)expression
type(expression)

C++中有4个类型转换符
static_cast
dynamic_cast
reinterpret_cast
const_cast
使用格式:xx_cast(expression)

class Person{
public:
    int m_age;
    
    virtual void run(){
        cout<<"Person::run()"<<endl;
    }
};

class Student:public Person{
    
};

class Car{};


//const_cast作用
//一般用于去除const属性,将const转换成非const
void const_cast_using(){
    
    const Person * p1 = new Person();
    //p1->m_age = 10;//不可以改变p1指向的内存空间的值
    
    
    //C语言的强制类型转换
    Person * p2 = (Person*)p1;
    p2->m_age = 20;
    cout<<"p1->m_age is "<<p1->m_age<<endl;
    
    
    //C++的强制类型转换
    Person * p3 = const_cast<Person*>(p1);
    p3->m_age = 30;
    cout<<"p1->m_age is "<<p1->m_age<<endl;
}


//dynamic_cast作用
//一般用于多态类型的转换,有运行时安全检测
void dynamic_cast_using(){

    Person * p = new Person();
    Student * s = new Student();
    
    cout<<"p is "<<p<<endl;//p is 0x100653180
    cout<<"s is "<<s<<endl;//s is 0x1006535a0
    
    //父类指针是可以指向子类对象的
    Person *p2 = s;
    
    
    //但子类指针指向父类对象时是不安全的。因为子类指针访问的内存空间明显要大于父类指针
    
    //C类型的强制转换
    Student * s2 = (Student*)p;//没有安全监测直接赋值
    cout<<"s2 is "<<s2<<endl;//s2 is 0x100653180
    
    
    //C++类型的强制转换
    Student * s3 = dynamic_cast<Student*>(p);//有运行时安全检测
    cout<<"s3 is "<<s3<<endl;//s3 is 0x0
    
    
    //可以交叉转换
    Car * car = dynamic_cast<Car*>(p);
    cout<<"car is "<<car<<endl;//car is 0x0
}


//static_cast作用
/**
 对比dynamic_cast,缺乏运行时安全检测     
 不能交叉转换(不是同一继承体系的,无法转换)     
 常用于基本数据类型的转换、非const转成const     
 适用范围较广     
 */
void static_cast_using(){
    
    Person * p1 = new Person();
    cout<<"p1 is "<<p1<<endl;//p1 is 0x1007a8b20
    
    //没有运行时安全监测
    Student * stu1 = static_cast<Student*>(p1);
    cout<<"stu1 is "<<stu1<<endl;//stu1 is 0x1007a8b20
    
    //不能交叉转换
    //Car * car = static_cast<Student*>(p1);
}


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

void reinterpret_cast_using(){
    
    //将100直接放到变量p的内存空间内
    long * p = reinterpret_cast<long*>(100);
    cout<<"p is "<<p<<endl;
    
    //将地址转为数字放到变量num内
    long num = reinterpret_cast<long>(p);
    cout<<"num is "<<num<<endl;
    
    
    //
    int  i1 = 10;
    double d1 = reinterpret_cast<double &>(i1);
    cout<<"d1 is "<<d1<<endl;
    
    
    //
    int i2 = 10;
    double d2 = (double)i2;
    cout<<"d2 is "<<d2<<endl;
}

C++11

一、auto

auto的使用
可以从初始化表达式中推断出变量的类型,大大简化编程工作
属于编译器特性,不影响最终的机器码质量,不影响运行效率

void autoUsing(){
    auto i = 10;//int
    auto str = "c++";//const char *
    auto p = new Person();//Person*
    p->run();
}

二、decltype

可以获取变量的类型

void decltype_using(){
    int a = 10;
    
    decltype(a) b = 20;//int
    
    typeof(a) c = 30;//int
}

三、nullptr

可以解决NULL的二义性问题
如果是空指针使用 nullptr

void funcTest(int v){
    cout<<"funcTest(int v)"<<endl;
}

void funcTest(int *v){
    cout<<"funcTest(int *v)"<<endl;
}

void nullptr_using(){
    //funcTest(NULL);//Call to 'funcTest' is ambiguous
    funcTest(0);
    funcTest(nullptr);
}

四、快速遍历

void fast_bianli(){
    int array[] = {11,22,33,44};
   
    for (int item : array) {
        cout<<"item is "<<item<<endl;
    }
    
    //更加简洁的初始化
    int array2[]{11,22,33,44};
    
    int a{10};
    cout<<"a is "<<a<<endl;
    
    int b(20);
    cout<<"b is "<<b<<endl;
}

五、lambda表达式

/**
 ◼ Lambda表达式
 有点类似于JavaScript中的闭包、iOS中的Block,本质就是函数
 
 完整结构: [capture list] (params list) mutable exception-> return type { function body }
 ✓capture list:捕获外部变量列表
 ✓params list:形参列表,不能使用默认参数,不能省略参数名
 ✓ mutable:用来说用是否可以修改捕获的变量
 ✓ exception:异常设定
 ✓return type:返回值类型
 ✓function body:函数体
 
 有时可以省略部分结构
 ✓[capture list] (params list) -> return type {function body}
 ✓[capture list] (params list) {function body}
 ✓[capture list] {function body}
 */

//1、C++11新特性:lambda表达式

void lambdaUsing(){
    //函数指针 p 指向一个函数地址 返回值是int,有两个参数 int int
    int(*p)(int,int);
    
    //lambda表达式的本质是函数
    int (*p1)(int ,int ) = [](int a,int b)->int{
        return a + b;
    };
    
    int c = p1(1,2);
    cout<<"c is "<<c<<endl;
    
    //直接调用
    int c1 = ([](int a1,int b1)->int{
        return a1+b1;
    })(2,3);
    cout<<"c1 is "<<c1<<endl;
    
    //参数和返回值可以省略
    int (*p2)(void) = []{
        return 100;
    };
    int c2 = p2();
    cout<<"c2 is "<<c2<<endl;
}

//lambda表达式作为函数参数
int exec(int a,int b,int(*func)(int ,int)){
    return func(a,b);
}
void lambdaUsing2(){
    cout<<exec(20, 10, [](int a,int b)->int{return a+b;})<<endl;
    cout<<exec(20, 10, [](int a,int b)->int{return a-b;})<<endl;
    cout<<exec(20, 10, [](int a,int b)->int{return a*b;})<<endl;
    cout<<exec(20, 10, [](int a,int b)->int{return a/b;})<<endl;
}


//2、变量捕获

void lambdaCatch(){
    int a = 10;
    int b = 20;
    
    //值捕获
    auto func = [a,b]{
        //a++;//无法访问变量a,也不存在局部变量a
        cout<<"a is "<<a<<endl;
        cout<<"b is "<<b<<endl;
    };
    
    //值捕获(=表示隐式捕获)
    auto func2 = [=]{
        cout<<"a is "<<a<<endl;
        cout<<"b is "<<b<<endl;
    };
    
    //a是值捕获,其余变量是地址捕获
    auto func3 = [&,a]{
        cout<<"a is "<<a<<endl;
        cout<<"b is "<<b<<endl;
    };

    
    //a是地址捕获,b是值捕获
    auto func4 = [&a,b]{
        //a++;//访问的外部变量a,因为是地址传递
        cout<<"a is "<<a<<endl;
        cout<<"b is "<<b<<endl;
    };
    
    //隐式捕获(地址捕获)
    auto func5 = [&]{
        cout<<"a is "<<a<<endl;
        cout<<"b is "<<b<<endl;
    };

    //a是地址捕获,其余变量是值捕获
    auto func6 = [=,&a]{
        cout<<"a is "<<a<<endl;
        cout<<"b is "<<b<<endl;
    };


    
    a++;
    b++;
    
    func();
    cout<<"------1-----"<<endl;
    func2();
    cout<<"------2-----"<<endl;
    func3();
    cout<<"------3-----"<<endl;
    func4();
    cout<<"------4-----"<<endl;
    func5();
    cout<<"------5-----"<<endl;
    func6();
    cout<<"------6-----"<<endl;
}


//3、mutable

void mutableUsing(){
    int a = 10;
    auto func = [a]() mutable{
        cout<<"++a is "<<++a<<endl;
    };
    
    //mutable的作用如下代码所示
//    auto func1 = [a](){
//        int b = a;
//        cout<<"++a is "<<++b<<endl;
//    };
    
    
    func();
    cout<<"a is "<<a<<endl;
}

C++14

//泛型lambda表达式

void fanxingLambda(){
    auto func = [](auto v1,auto v2){
        return v1 + v2;
    };
    
    cout<<func(10,20.5)<<endl;
}

//对捕获的变量进行初始化

void initCatchVar(){
    int a ;
    auto func = [a = 10]{
        cout<<a<<endl;
    };
    
    func();
    
    //这里仍是未初始化的变量a
    cout<<a<<endl;
}

C++17

//可以进行初始化的if、switch语句

void initIfAndSwich(){
    //变量a、b的作用域是它所在的if语句,以及其后面的if-else语句
    if (int a = 10;a>10) {
        a = 1;
    }else if(int b = 20;a>b && b>10){
        b = 2;
        a = 2;
    }else{
        a = 3;
        b = 4;
    }
    
    
    //变量a的作用域是它所在swich语句
    switch (int a = 10;a) {
        case 1:
            break;
        case 5:
            break;
        case 10:
            break;
        default:
            break;
    }
}

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.