浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第11课 新型的类型转换

Posted on 2016-04-10 20:35  浅墨浓香  阅读(465)  评论(0编辑  收藏  举报

1. C方式的强制类型转换

(1)转换形式

  ①(Type)(Expression)

  ②Type(Expression) //老式的

【编程实验】粗暴的类型转换

#include <stdio.h>

typedef void PF(int);

struct Point
{
    int x;
    int y;
};

int main()
{
    int v = 0x12345;
    PF* pf = (PF*)v;
    char c = char(v);//老式写法,很像函数调用
    Point* p = (Point*)v;

    pf(5);

    printf("p->x = %d\n", p->x);
    printf("p->y = %d\n", p->y);

    return 0;
}

(2)强制类型转换存在的问题

  ①过于粗暴:任意类型之间都可以进行转换,编译器很难判断其正确性

  ②难于定位:在源码中无法快速定位所有使用强制类型转换的语句

2. C++中新式的4种强制类型转换

(1)用法:xxx_cast(Type)(Expression)

(2)4种类型

类型

适用范围

举例

备注

static_cast

基本类型之间(可相互隐式转换)

②不能用于基本类型的指针之间(因为该类型的指针间不能互相隐式转换

③类与子类对象之间的转换或类指针间转换。(子类对象可隐式转换为父类(单向,反之不行。指针类型也一样)

int i = 0;

char c = 'A';

 

int* pi = &i;

char* pc = &c;

 

c = static_cast<char>(i); //ok,c =i 或 i=c(即可双向隐式转换

 

//不能用于基本类型的指针间转换

pc = static_cast<char*>(pi);//oops,因为 pi不能隐式转换为pc

①一般适用于两者间可隐式转换的类型(双向或单向均可)。

②编译时检查,可用于非多态类指针间的转换,但不支持交叉转换。

③在类层次间进行转换时,上行转换static_cast与dynamic_cast效果是一样的,但下行转换时dynamic_cast具有类型检查功能,比static_cast更安全。

const_cast

目标类型(即尖括号内的类型)必须是指针或引用

//i有内存,因别名,每次从内存读取i

const int& i = 1;//i为引用

int& a = const_cast<int&>(i);

 

const int j = 1;

//为j分配内存,但不会去用它,从符号表中取j

int&  b = const_cast<int&>(j);

 

a = 5; //i==5;a==5;

b = 3; //j==1,b==3;

用于去除变量的const属性

reinterpret_cast

①用于指针类型间

②用于整数和指针类型之间

typedef void PF(int);

 

int i = 0;

char c = 'c';

 

int* pi = reinterpret_cast<int*>(&c); //因为&c(char*类型)不能隐式转为pi。

char*pc = reinterpret_cast<char*>(&i);//&i不能隐式转为char*

 

PF*pf= reinterpret_cast<PF*>(0x12345678);

 

//以下错,要用static_cast

c = reinterpret_cast<char>(i); //oops,因为i可隐式转为c。

①一般适用于不能隐式转换的类型之间的转换(双向均不能)

②reinterpret_cast直接从二进制位进行复制,是一种极其不安全的转换。

dynamic_cast

①用于有继承关系的类指针间。

②用于有交叉关系的类指针之间(即继承图上通过继承路径的可达的两个类之间,如,多继承的两个基类之间等。)

 

详见后面章节的分析

①dynamic_cast具有类型检查的功能,目标类型必须是类的指针或引用

②运行时检查,用于多态的类型转换(上转,下转和交叉转换),只能转换指针和引用且需要虚函数的支持,才不会报错。而static_cast转换,即使基类没有虚函数,编译也不会报错,但这种转换不完全。

③dynamic_cast支持交叉转换,而satic_cast不支持这种转换

【实例分析】新式类型转化初探

#include <stdio.h>

void static_cast_demo()
{
    int i = 0x12345;
    char c = 'c';
    int* pi = &i;
    char* pc = &c;

    c = static_cast<char>(i);//基本类型

    //基本类型的指针间,非法
    //pc = static_cast<char*>(pi);  //pi不能隐式转为pc,须用reinterpret_cast!
}

void const_cast_demo()
{

    //用常量初始化引用,要分配内存。故j为变量,因加const而成只读变量
    const int& j = 1;//j为引用--》只读变量,说明j不能做为左值而己
    int& k = const_cast<int&>(j); //转为普通引用,k就是j的别名

    k = 5;

    printf("k = %d\n", k); //5
    printf("j = %d\n", j); //5

    const int x = 2; //x为常量
    int& y = const_cast<int&>(x);//此时,会为x分配内存
    //int z = const_cast<int>(x);  //oops,目标类型只能是引用或指针

    y = 3;

    printf("x = %d\n", x); //2
    printf("y = %d\n", y); //3
    printf("&x = %d\n", &x);
    printf("&y = %d\n", &y); //x与y的内存地址是相同的
}

void reinterpret_cast_demo()
{
    int i = 0;
    char c = 'c';
    int* pi = &i;
    char* pc = &c;

    pc = reinterpret_cast<char*>(pi); //ok,指针间
    pi = reinterpret_cast<int*>(pc);  //ok,指针间
    pi = reinterpret_cast<int*>(i);   //ok,整数与指针间
    //c  = reinterpret_cast<char>(i);   //oops,基本类型间转换,要用static_cast

}

void dynamic_cast_demo()
{
    int i = 0;
    int* pi = &i;
    char* pc = dynamic_cast<char*>(pi);//oops,目标类型应为类的指针或引用
}

int main()
{
    static_cast_demo();
    const_cast_demo();

    reinterpret_cast_demo();
    dynamic_cast_demo();
    return 0;
}

3. 小结

(1)C方式的强制类型转换

  ①过于粗暴;②潜在的问题不易被发现;③不易在代码中定位

(2)新式类型转换以C++关键字的方式出现

  ①编译器能够帮助检查潜在的问题

  ②非常方便的在代码中定位

  ③支持动态类型识别(dynamic_cast)