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

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

1.类型转换

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

(type)expression
type(expression)

int main(){ 
    int a = 10;
    double d = static_cast(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(expression)

I.const_cast

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

const Person *p1 = new Person();
Person *p2 = const_cast(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(p1);//不安全,子类指针指向父类对象
    Student *stu2 = dynamic_cast(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(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(a);

Person *p1 = new Person();
const Person *p2 = static_cast(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(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(0x100);
int b = reinterpret_cast(p);

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

int *p = reinterpret_cast(0x100);
int b = reinterpret_cast(p);
//无需写成引用
int a = 10;
double d = reinterpret_cast(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新特性)