一 typeid与dynamic_cast

1)RTTI, Runtime Type Identification (RTTI) or Run-time type information (RTTI),表示在运行时动态决定变量的类型,来调用正确的虚函数。 RTTI在VS2008中默认为关闭,可以通过修改编译选项Enable Run-Time Type Info 为 Yes,来启用RTTI,只有当启动RTTI时,用来RTTI功能的typeid和dynamic_cast才能正常工作。

2)type_info,用来描述类型信息。type_info存储了它所描述的类型的名字。RTTI就是使用type_info来实现的。type_info的定义如下:

Code
class type_info {
public:
  virtual ~type_info();
  bool operator== (const type_info& rhs) const;
  bool operator!= (const type_info& rhs) const;
  bool before (const type_info& rhs) const;
  const char* name() const;
private:
  type_info (const type_info& rhs);
  type_info& operator= (const type_info& rhs);
};

问题:RTTI怎么实现那?对象,type_info,虚函数怎么关联那?《深入C++对象模型》中说在虚函数表的开始存储了类型信息?经过高手指点确实是在虚函数表的前面还有一个指针来存储RTTICompleteObjectLocator,其中包含类型信息TypeDescriptor,类型继承信息RTTIClassHierarchyDescriptor,类继承信息里包含了基类的信息RTTIBaseClassArray。可以参考:http://www.cppblog.com/dawnbreak/archive/2009/03/12/76354.html。

3)typeid,在运行时获得对象的类型,typeid()返回的是const type_info&,而 type_info包含了对象真实类型的名字。typeid能被用来获取一个引用对象或指针指向的对象的运行时的真实类型。当然如果对象为null或编译时没有使用/GR的话,typeid的会抛出异常bad_typeid exception或__non_rtti_object。实例代码:

Code
class Base 
{
public:
    virtual void f(){ }
};
 
class Derived : public Base 

public:
    void f2() {}
};

void main ()
{
    Base *pB = new Derived();
    const type_info& t = typeid(*pB);cout <<t.name() << endl;
    delete pB;

Derived d;
    Base& b = d;
    cout << typeid(b).name() << endl;
}

运行结果:

4)dynamic_cast,用来运行时的类型转化,需要/GR来正确运行。
适用:
第一,用于所有的父子和兄弟间指针和引用的转化,有类型安全检查; 
第二,对指针类型,如果不成功,返回NULL,对引用类型,如果不成功,则抛出异常; 
第三,类型必须要有虚函数,且打开/GR编译选项,否则不能使用dynamic_cast。
实例代码:

Code
class AA 
{
public:
    virtual void do_sth(){ std::cout<<"AA\n"; }
};
class BB 
{
public:
    virtual void do_sth(){ std::cout<<"BB\n"; }
};
class CC : public AA, public BB
{
public:
    virtual void do_sth(){ std::cout<<"CC\n"; } 
};

void DynamicCastTest()
{
    AA *pA = new CC;
    BB *pB = dynamic_cast<BB*>(pA);
    if(pB != NULL)
        cout << "cast successful!" << endl;
    CC *pC = dynamic_cast<CC*>(pA);
    if(pC != NULL)
     cout << "cast successful!" << endl;
}

二 其他cast

1)隐式转化,不需要任何操作符,转化被自动执行,当一个值被赋值到它所兼容的类型时。
适用:
第一,内置基本类型的兼容转化;
第二, 子类指针,引用向父类的转化;

实例:

Code
class A
{
public:
    virtual ~A(){}
};
class B : public A
{
};

void ImplicitCast()
{
    short a = 2000;
    int b;
    b = a;

double d = 10.05;
    int i;
    i = d;

int j = 75;
    char c;
    c = j;

A* pA = new B();
}

2)强制类型转化,即我们常说的C风格的类型转化,基本上可以用于所有的转化,但是没有意义的转化除外,但是父子类,兄弟间的转化没有类型检查可能导致运行是错误。
适用:
第一,基本类型转化;
第二,void*到其他指针的转化;
第三,去除const;
第五,函数指针的转化;
第六,父子类转化,但是多重继承和兄弟转化,可能有运行时错误,没有类型检查;
第七,任何两个类,但是没有实际意义,运行可能出错;
第八,不能用于没有意义的转化,严厉禁止,例如,你不能用static_cast象用C风格的类型转换一样把struct转换成int类型,或者把double类型转换成指针类型;
第九,在C++一般更推荐新加的static_cast,const_cast,dynamic_cast和reinterpret_cast转化方式;

实例:

Code
class CDummy 
{
public:
    CDummy(float x, float y)
    {
        i = x;
        j = y;
    }
private:
    float i,j;
};

class CAddition 
{
public:
    CAddition (int a, int b) { x=a; y=b; }
    int result() { return x+y;}
private:
    int x,y;
};

int Testing()
{
    std::cout << "Testing" << std::endl;
    return 10;
}

void ExplicitCast()
{
    double r = (double)1 / 3;

int *pi = new int(10);
    void *pV;
    pV = pi;
    int *pj = (int*)pV; // 或 int *pj = int*(pV);

const int* pa = new int(20);
    int *pb;
    pb = (int*)pa;
    *pb = 30;
    std::cout << *pa << std::endl;

typedef void (*Fun)();

Fun f = (Fun)Testing;
    f();

// 多重继承或将兄弟间的转化可能会出错

// 虽然可以正确的编译,但是运行有问题,所以我们不做没有意义的转化
    //CDummy d(10,30);
    //CAddition * padd;
    //padd = (CAddition*) &d;
    //std::cout << padd->result();

// 不做没有意义的转化
    //// error
    //struct st{int i; double d;};
    //st s;
    //int x = (int)s; //c2440

//double y = 10.0;
    //int *p = (int*)y; // c2440
}

3)static_cast在功能上基本上与C风格的类型转换一样强大,含义也一样。
它也有功能上限制:
第一,不能兄弟间转化,父子间转化没有类型安全检查,有可能会导致运行时错误,父子兄弟的动态转化应该适用dynamic_cast;
第二,不能去除const,适用专用的const_cast;
第三,不能用于两个没有继承关系的类,当然实际上这样的转化也是没有意义的;
第四,当然也不支持没有意义的转化,例如,你不能用static_cast象用C风格的类型转换一样把struct转换成int类型,或者把double类型转换成指针类型;

4)const_cast,用来修改类型的const或volatile属性。

适用:
第一,常量指针被转化成非常量指针,并且仍然指向原来的对象;
第二,常量引用被转换成非常量引用,并且仍然指向原来的对象;
第三,常量对象被转换成非常量对象;

实例:

Code
void ConstCastTest()
{
    const int* pa = new int(20);
    int *pb;
    pb = const_cast<int*>(pa);
    *pb = 30;
    std::cout << *pa << std::endl;
}

5)reinterpret_cast,此转型操作符的结果取决于编译器,用于修改操作数类型,非类型安全的转换符。
适用:
一般不推荐使用,但是一般用来对函数指针的转化。
实例:

Code
// 不可以移植,不推荐使用
int ReinterpretTest()
{
    struct dat { short a; short b;};
    long value = 0x00100020;
    dat * pd = reinterpret_cast<dat *> (&value);
    std::cout << pd->a << std::endl; // 0x0020
    std::cout << pd->b << std::endl; // 0x0010
    return 0;
}

typedef void (*Fun)();

int Testing()
{
    std::cout << "Testing" << std::endl;
    return 10;
}

void ReinterpretTest2()
{
    //Fun f = (Fun)Testing;
    //f();
    Fun f = reinterpret_cast<Fun>(Testing);
    f();
}

三 总结

在C++一般更推荐新加的static_cast,const_cast,dynamic_cast和reinterpret_cast转化方式;

转载于:https://www.cnblogs.com/itech/archive/2009/03/01/1398230.html

[C++对象模型][10]类型转化相关推荐

  1. Android笔记 - android 类型转化错误

    今天遇到一bug,报错如下 09-15 11:07:29.075 7669 7669 E AndroidRuntime: FATAL EXCEPTION: main 09-15 11:07:29.07 ...

  2. mysql 时间类型转化_Mysql 字段类型转化 和 时间类型相关处理

    I) 字段类型转化 MySQL 的CAST()和CONVERT()函数可用来获取一个类型的值,并产生另一个类型的值.两者具体的语法如下: CAST(value as type); CONVERT(va ...

  3. js中字符串类型转化toString、parseInt、parseFloat、Number

    全栈工程师开发手册 (作者:栾鹏) js系列教程3-字符串.正则表达式全解 js中字符串类型转化 其他类型转化为字符串: 代码如下: var num= 19; // 19 var myStr = nu ...

  4. java赋值运算的类型转换出新的问题_Java中byte、short、char、int、long运算时自动类型转化问题...

    -------------------------------------------------------------------------------------------------- ★ ...

  5. Java的知识点6—— 强制类型转换、基本类型转化时常见错误和问题、 简单的键盘输入和输出

     强制类型转换 强制类型转换,又被称为造型,用于显式的转换一个数值的类型.在有可能丢失信息的情况下进行的转换是通过造型来完成的,但可能造成精度降低或溢出. public class Test2 {pu ...

  6. C++字符串类型转化

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105090125 字 ...

  7. Java黑皮书课后题第2章:2.18(打印表格)编写程序,显示下面的表格,将浮点数值类型转化为整数

    2.18(打印表格)编写程序,显示下面的表格,将浮点数值类型转化为整数 题目 题目描述 代码 方法评价 化繁为简:强制(数据)类型转换 题目 题目描述 2.18(打印表格)编写程序,显示下面的表格,将 ...

  8. [java]常用类型转化

    1,字符串和其他类型的转化 字符串转化为其他类型 字符串转化为int String s = "123"; int myint=Integer.valueOf(s) + 1; Sys ...

  9. Asp.net 面向接口可扩展框架之类型转化基础服务

    新框架正在逐步完善,可喜可贺的是基础服务部分初具模样了,给大家分享一下 由于基础服务涉及面太广,也没开发完,这篇只介绍其中的类型转化部分,命名为类型转化基础服务,其实就是基础服务模块的类型转化子模块 ...

最新文章

  1. idea编辑器无法识别jdk
  2. 图解WinCE6.0下的内核驱动和用户驱动
  3. 51nod1812树的双直径(换根树DP)
  4. ICT学习笔记(3)IP编址
  5. Maven学习总结(10)——使用Maven编译项目gbk的不可映射问题
  6. PaddlePaddle(2)——数据获取与处理(以CV任务为主)
  7. p8b75-m修改bios文件_傻瓜式方法:VMWARE使用NAT方式彻底解决开发板无法挂载ubuntu文件的难题...
  8. python最全画地图,可视化数据
  9. 使用Safari只要打开echarts图表的网址会使Safari未响应
  10. 利用excel搭建动态图表
  11. win10修改用户名_大神帮您win10系统用户文件夹改名的修复方法
  12. Twitter在15岁终于迎来蜕变
  13. 计算机硬盘属于主机还是外部设备,计算机主机的外部连接分别是什么?
  14. JAVA学习日记DAY09--javaweb的一些简单应用
  15. PyCharm 的使用(二)
  16. mysql的sqlyog学习笔记(高级查询部分)(代码用命令行显示 )
  17. 包含重复元素的全排列
  18. Pandas-DataFrame使用
  19. 查询课程名称为“数学“,且分数低于60的学生姓名和分数
  20. sdutacm- 数据结构实验之排序一:一趟快排

热门文章

  1. lettuce配置_skywalking与lettuce哨兵模式
  2. cmd安装mysql_MySQL windows下cmd安装操作
  3. tushare学习文档_介绍一个python股票分析包tushare——韭菜的自我修养
  4. 《南溪的目标检测学习笔记》——模型预处理的学习笔记
  5. Deformable-DETR的学习笔记
  6. Android编程中利用AudioTrack播放PCM数据在音频的最后出现重复回声现象的解决方案
  7. 请解释一下 str db 0dh,0ah,‘$‘ 这个汇编语句什么意思?
  8. 【oracle】除数为0
  9. Rosie's Frankly Speaking
  10. DirectX11 With Windows SDK--07 添加光照与常用几何模型、光栅化状态