C++中的类型转换分两种:隐式类型转换和显式类型转换。

隐式转换,是标准的转换,很多时候是默认情况下由编译器进行转换;

显式转换,在C++中有四个类型的转换符:static_cast、dynamic_cast、const_cast、reinterpret_cast。

1. static_cast用法

      转换格式:

  1. 将expression转换为type_id类型,主要用于非多态类型之间的转换;
  2. static_cast转换,不能转换掉expression的const、volatile、和_unaligned属性

static_cast<type_id>(expression)

  • 场景1,用于类层次结构中,基类和子类之间的指针或引用的转换

【1】上行转换,子类指针或引用转父类,这种转换是安全的。

       多态类型之间转换:使用static_cast和使用dynamic_cast效果一样;

         非多态类型之间转换:只能使用static_cast,使用dynamic_cast会编译报错

//先定义一个父类A,和子类B
class A
{
public:virtual void Func() { cout << "A::Func()" << endl; }
};class B : public A
{
public:void Func() override { cout << "B::Func()" << endl; }
};int main()
{A* pa = new B;A* a = static_cast<B*>(pb);//ok,转换是安全的B* pb = new B;A* a = static_cast<B*>(pb);//ok,转换是安全的return 0;
}

【2】下行转换,父类指针或引用转子类,这种转换是不安全的

int main()
{//B* pb = new A;    //error,编译报错,无法从A*转换为B*A* pa = new A;B* b = static_cast<B*>(pa); //ok,编译无误,b != nullptr,这是不安全的,没有做类型检查return 0;
}
  • 场景2,用于基本数据类型之间的转换,如把int转成char,把int转换成enum等等,这种转换是不安全的

char转int,是安全的

int iVar1 = 10;
char cVar1 = 'a';
iVar1 = static_cast<int>(cVar1);
cout << iVar1 << endl;

int转char,是不安全的,由ASSIC表得出,只有int[32,126]区间,转换才是安全的

int iVar2 = 10;
char cVar2 = 'a';
cVar2 = static_cast<char>(iVar2);
cout << cVar2 << endl;
  • 场景3,把void指针转换成目标类型,这种转换是及其不安全的,编译报错
int a = 10;
void* pa = &a;int b = static_cast<int>(pa);
cout << b << endl;float c = static_cast<float>(pa);
cout << c << endl;

  •  另外,static_cast转换,不能转换掉expression的const、volatile、和_unaligned属性
const int iVar = 110;
int* pVar1 = static_cast<int*>(&iVar);//编译报错
const int* pVar2 = static_cast<const int*>(&iVar);//编译无误,通过

2. dynamic_cast用法

 转换格式:

  1. 将expression转换为type-id类型,type-id必须是类的指针或引用或void*;
  2. 如果type-id是指针类型,那么expression也必须是一个指针;
  3. 如果type-id是引用类型,那么expression也必须是一个引用;
  4. dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换;其中进行上行转换时,dynamic_cast和static_cast的效果一样;进行下行转换时,dynamic_cast具有类型检查功能,比static_cast更安全;
  5. 在多态类型之间转换主要使用dynamic_cast,因为类型提供了运行时信息。

dynamic_cast<type_id>(expression)

  • 场景1,用于类层次结构中,基类和子类之间的指针或引用的转换

【1】上行转换(单继承),子类指针或引用转父类,这种转换是安全的。

 多态类型之间转换:使用static_cast和使用dynamic_cast效果一样;

         非多态类型之间转换:只能使用static_cast,使用dynamic_cast会编译报错

class A
{
public:virtual void Func(){cout << "A::Func()" << endl;}
};class B: public A
{
public:virtual void Func() override{cout << "B::Func()" << endl;}
};int main()
{B* pb = new B;A* a1 = dynamic_cast<A*>(pb); //OKa1->Func();A* pa = new B;A* a2 = dynamic_cast<A*>(pa); //OKa2->Func();return 0;
}

如果Func为virtual,输出结果:        

如果Func为非virtual,输出结果:    


【2】上行转换(多重继承),子类指针或引用转父类,这种转换是安全的

class A
{
public:virtual void Func(){}
};class B: public A
{
public:virtual void Func() override{}
};class C : public B
{
public:virtual void Func() override{}
};int main()
{C* c = new C;B* b = dynamic_cast<B*>(c); //OKA* a = dynamic_cast<A*>(c); //OK
}
  • 场景2,将类转换为void*,A类和B类中必须包含虚函数。

        原因,类中存在虚函数,说明有想让基类指针或引用指向派生类对象的情况,此时转换才有意义;由于运行时类型检查需要运行时类型信息(该运行信息存储在类的虚函数表中),所以只有定义了虚函数的类才有虚函数表。

class A
{
public:virtual void Func() {} //注意关键字virtual// ......
};
class B : public A
{
public:virtual void Func() {} //注意关键字virtual// ......
};
int main()
{A *pA = new A;B *pB = new B;void *pV = dynamic_cast<void *>(pA); // pV points to an object of ApV = dynamic_cast<void *>(pB); // pV points to an object of Bsystem("pause");return 0;
}

去掉virtual关键字,会编译报错

  • 场景3,如果expression类型是type-id的基类,使用dynamic_cast进行转换时,在运行时会检查expression是否真正的指向一个type-id类型的对象。如果是,则能进行正确的转换,得到真正的值;否则返回NULL;如果是引用,则在运行时就会抛出异常。

【1】下行转换(单继承),父类指针或引用转子类,会做类型安全检查,这种转换是安全的

class A
{
public:virtual void Func(){cout << "A::Func()" << endl;}
};class B: public A
{
public:virtual void Func() override{cout << "B::Func()" << endl;}
};int main()
{//B* pb = new A;             //error,编译报错,无法从父类A*转换为子类B* /** 由父类A*转换子类B*,使用dynamic_cast能做到安全检查,转换失败会返回null;* 使用static_cast不安全*/A* pa1 = new B;B* b1 = dynamic_cast<B*>(pa1); //ok,编译无误,b != nullptrif (nullptr != b1) {b1->Func();}A* pa2 = new A;B* b2 = dynamic_cast<B*>(pa2); //ok,编译无误,b = nullptrif (nullptr != b2) {b2->Func();}return 0;
}

【2】 对于一些复杂继承关系,使用dynamic_cast进行转换是存在一些陷阱的

如下做法存在陷阱,

class A
{virtual void Func() = 0;
};
class B : public A
{void Func() { cout << "B::Func()" << endl; }
};
class C : public A
{void Func() { cout << "C::Func()" << endl; };
};
class D : public B, public C
{void Func() { cout << "D::Func()" << endl; }
};
int main()
{D *pD = new D;/** B和C都继承了A,并且都实现了虚函数Func,导致在进行转换时,无法进行抉择应该向哪个A进行转换*/A *pA = dynamic_cast<A *>(pD); // pA = NULL//pA->Func();system("pause");return 0;
}

正确的做法是,像多重继承关系这种情况,需要把子类逐步转换到父类

int main()
{D *pD = new D;B *pB = dynamic_cast<B *>(pD);A *pA = dynamic_cast<A *>(pB);return 0;
}

3. const_cast用法

 转换格式:const_cast用来将类型的const、volatile和_unaligned属性移除。

  1. 常量指针被转换为非常量指针,并且仍然指向原来的对象;
  2. 常量引用被转换为非常量引用,并且仍然引用原来的对象;
  3. 不能直接对非指针和非引用的变量使用const_cast操作符去直接移除它的const、volatile和__unaligned属性。

const_cast <type-id> (expression)

  • 场景1,常量指针转非常量指针
class A
{
public:A() :m_iA(10) {}int m_iA;
};
int main()
{//常量指针转非常量指针const A *pA = new A;//pA->m_iA = 100;         //error,pA常量指针,指向的内容不能修改cout << pA->m_iA << endl;A *pB = const_cast<A*>(pA);    //去const属性pB->m_iA = 100;               //通过指针,修改值//指针pA和pB指向同一个对象cout << pA->m_iA << endl;cout << pB->m_iA << endl;return 0;
}
  • 场景2,指针常量转非指针常量
class A
{
public:A() :m_iA(10) {}int m_iA;
};int main()
{//常量指针转非常量指针A * const pA1 = new A;pA1->m_iA = 100;                //ok,pA是指针常量,指向的内容可以修改cout << pA1->m_iA << endl;A *pA2 = new A;//pA1 = pA2;                  //error,pA是指针常量,指向的地址不能修改A *pB = const_cast<A*>(pA1);  //去const属性pB = pA2;                        //通过指针,修改值pB->m_iA = 111;//指针pA和pB指向同一个对象cout << pA1->m_iA << endl;cout << pA2->m_iA << endl;cout << pB->m_iA << endl;return 0;
}
  • 场景3,常量引用转非常量引用
int main()
{const int &num = 10;//num = 100;         //error,不能给常量赋值int &num2 = const_cast<int&>(num);num2 = 100;return 0;
}
  •  场景4,不能给非常量指针和引用使用const_cast
int main()
{const int num1 = 10;//int num2 = const_cast<int>(num1);   //error,编译报错,无法从“const int”转换为“int”    return 0;
}

4. reinterpret_cast用法

        转换格式:

reinterpret_cast <type-id> (expression)

reinterpret_cast后的尖括号中的type-id类型必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。

浅谈static_cast、dynamic_cast、const_cast、reinterpret_cast用法相关推荐

  1. C/C++中的数据类型转换()/static_cast/dynamic_cast/const_cast/reinterpret_cast

    文章目录 前言 数据类型自动转换 C语言中的强制类型转换 C++中的强制类型转换 static_cast dynamic_cast const_cast reinterpret_cast 强转关键字的 ...

  2. 显式强制类型转换static_cast, dynamic_cast, const_cast, reinterpret_cast

    显式强制类型转换(cast)包括以下操作符: static_cast,  dynamic_cast, const_cast, reinterpret_cast,对各种显式类型转换解释: static_ ...

  3. static_cast, dynamic_cast, const_cast,reinterpret_cast探讨

    http://www.cnblogs.com/chio/archive/2007/07/18/822389.html 首先回顾一下C++类型转换: C++类型转换分为:隐式类型转换和显式类型转换 第1 ...

  4. 类型转换操作符:static_cast, dynamic_cast, const_cast, reinterpret_cast.

    呵呵,今天来好好看看着几个转换操作符的用法.以前老是看着眼熟,但是用着手生.今天决定搞定这些个东西. 在C语言中类型转换有几种方式: 1.      (expression). 在表达式外边加括号,由 ...

  5. C++ 11 深度学习(五)类型转换:static_cast dynamic_cast const_cast reinterpret_cast

    四种cast 通用形式:强制类型转换名<type>(express) @强制类型转换名,以上四种  :@type:想要转成成的目标类型 : @express,需要转换的目标 static_ ...

  6. C++ static_cast dynamic_cast const_cast reinterpret_cast使用总结

    因为原来C风格的暴力万能类型转换容易导致运行时出错,所以要引入分类更清晰提前发现错误的转换语法. 对象的类型转换包含了对象的引用或指针. 1.static_cast是编译器默认选项,该运算符把expr ...

  7. 类型转换static_cast,dynamic_cast,const_cast,reinterpret_cast等

    一.隐式类型转换 系统自动进行,不需要程序开发人员介入. int m = 3 +45.6; //把小数部分截掉,也属于隐式类型转换的一种行为. doublen = 3 +45.6; 二.显示类型转换( ...

  8. C++中static_cast, dynamic_cast, const_cast用法/使用情况及区别解析

    目录 第1部分. 隐式类型转换 第2部分. 显式类型转换 static_cast dynamic_cast reinpreter_cast const_cast 首先回顾一下C++类型转换: C++类 ...

  9. C++类型转换(static_cast,dynamic_cast,const_cast和reinterpret_cast)

    一.概述 类型转换(cast)是将一种数据类型转换成另一种数据类型.例如,如果将一个整型值赋给一个浮点类型的变量,编译器会暗地里将其转换成浮点类型(即 隐式转换 ).转换是非常有用的,但是它也会带来一 ...

  10. When should static_cast, dynamic_cast and reinterpret_cast be used?

    这是我偶然在 http://stackoverflow.com/questions/ 网页上发现的一个问题(类似博客园的博问),问题主要是关于询问应该怎样使用,以及何时使用C++里面的这几种类型转换操 ...

最新文章

  1. SpringMVC集成Tiles布局引擎框架
  2. Python 的编码问题UnicodeDecodeError: 'ascii' codec can't decode byte ××× in postition
  3. java-模拟存放String类型数据的栈
  4. VC2019消息框编程总结
  5. poj 2373(单调队列优化dp)
  6. 转:PHP非阻塞模式
  7. ClickOnce部署(3):使用证书
  8. python opencv手册_教你用Python实现5毛钱特效(给你的视频来点料)
  9. Java 必须掌握的 12 种 Spring 常用注解
  10. AccuREST Stub Runner发布
  11. centOS安装Ftp
  12. Python 读取json文件
  13. 拔刀剑服务器r87修复版,我的世界拔刀剑mod刀剑修复教程
  14. django本地安装mysql_Ununtu 15.04 安装MySql(Django连接Mysql)
  15. C++自动类型转化--特殊构造函数方法和重载的运算符方法
  16. 《女士品茶》读书笔记
  17. 清华EMBA课程系列思考之十七(1) -- 新企业的孵化与创业投资
  18. Sub-center ArcFace
  19. 自学车载以太网笔记(1)
  20. oracle查看日期是第几周

热门文章

  1. 无法停止通用卷的解决方法
  2. 可在广域网部署运行的QQ高仿版 -- GG叽叽V3.0,完善基础功能(源码)
  3. 数字冰雹创始人邓潇专访:2017大数据可视化的关键技术及行业应用
  4. A类、B类、C类和D类期刊
  5. 简易微信小程序签到功能
  6. pygame入门小游戏(外星人入侵(2):为窗口设计背景颜色以及背景图片)
  7. 水塘采样(Reservoir sampling)算法
  8. 【个人成长】高效能人士的七个习惯
  9. 工具类|快递物流的订阅与查询
  10. php+Mysql分页 类和引用详解