文章目录

  • 前言
  • 数据类型自动转换
  • C语言中的强制类型转换
  • C++中的强制类型转换
    • static_cast
    • dynamic_cast
    • const_cast
    • reinterpret_cast
    • 强转关键字的选择
  • 总结

前言

C/C++属于静态语言,也就是在编译时变量的数据类型即可确定的强类型语言。当不同的数据类型在一起运算或者相互赋值的时候,就需要进行数据类型转换。不同数据类型占用的内存空间不同,而各种数据类型的转换时有规则的,一种通用的规则就是“小转大”自动进行,“大转小”需要强制执行。这里的“大”和“小”指的是数据范围。

为什么会有数据范围大小的区别呢?这就和饭店里的盘子一样,不同的菜肴通常使用不同的盘子,盘子有大有小,如果把小盘子里的菜装到大盘子里没有问题,但是把大盘子里的菜放到小盘子中就会溢出来,假设都使用大盘子就不会产生溢出的问题,但是这样会产生空间的浪费。而C/C++中不同类型的变量占用的内存空间不同与这些盘子非常相似,当范围小的变量赋值给范围大的变量时没有问题,但是反过来也会出现溢出。

数据类型自动转换

当不同类型的变量同时运算时就会发生数据类型的自动转换,以常见的 charshortintlongfloatdouble 这些类型为例,如果 charint 两个类型的变量相加时,就会把 char 先转换成 int 再进行加法运算,如果是 intdouble 类型的变量相乘就会把 int 转换成 double 再进行运算。

自动转换的行为如下图所示,方向是从左往右自动进行:

#mermaid-svg-VZGeguoSsMw8gsBF .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-VZGeguoSsMw8gsBF .label text{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF .node rect,#mermaid-svg-VZGeguoSsMw8gsBF .node circle,#mermaid-svg-VZGeguoSsMw8gsBF .node ellipse,#mermaid-svg-VZGeguoSsMw8gsBF .node polygon,#mermaid-svg-VZGeguoSsMw8gsBF .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-VZGeguoSsMw8gsBF .node .label{text-align:center;fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF .node.clickable{cursor:pointer}#mermaid-svg-VZGeguoSsMw8gsBF .arrowheadPath{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-VZGeguoSsMw8gsBF .flowchart-link{stroke:#333;fill:none}#mermaid-svg-VZGeguoSsMw8gsBF .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-VZGeguoSsMw8gsBF .edgeLabel rect{opacity:0.9}#mermaid-svg-VZGeguoSsMw8gsBF .edgeLabel span{color:#333}#mermaid-svg-VZGeguoSsMw8gsBF .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-VZGeguoSsMw8gsBF .cluster text{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-VZGeguoSsMw8gsBF .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-VZGeguoSsMw8gsBF text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-VZGeguoSsMw8gsBF .actor-line{stroke:grey}#mermaid-svg-VZGeguoSsMw8gsBF .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-VZGeguoSsMw8gsBF .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-VZGeguoSsMw8gsBF #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-VZGeguoSsMw8gsBF .sequenceNumber{fill:#fff}#mermaid-svg-VZGeguoSsMw8gsBF #sequencenumber{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF #crosshead path{fill:#333;stroke:#333}#mermaid-svg-VZGeguoSsMw8gsBF .messageText{fill:#333;stroke:#333}#mermaid-svg-VZGeguoSsMw8gsBF .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-VZGeguoSsMw8gsBF .labelText,#mermaid-svg-VZGeguoSsMw8gsBF .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-VZGeguoSsMw8gsBF .loopText,#mermaid-svg-VZGeguoSsMw8gsBF .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-VZGeguoSsMw8gsBF .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-VZGeguoSsMw8gsBF .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-VZGeguoSsMw8gsBF .noteText,#mermaid-svg-VZGeguoSsMw8gsBF .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-VZGeguoSsMw8gsBF .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-VZGeguoSsMw8gsBF .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-VZGeguoSsMw8gsBF .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-VZGeguoSsMw8gsBF .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF .section{stroke:none;opacity:0.2}#mermaid-svg-VZGeguoSsMw8gsBF .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-VZGeguoSsMw8gsBF .section2{fill:#fff400}#mermaid-svg-VZGeguoSsMw8gsBF .section1,#mermaid-svg-VZGeguoSsMw8gsBF .section3{fill:#fff;opacity:0.2}#mermaid-svg-VZGeguoSsMw8gsBF .sectionTitle0{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF .sectionTitle1{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF .sectionTitle2{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF .sectionTitle3{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-VZGeguoSsMw8gsBF .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF .grid path{stroke-width:0}#mermaid-svg-VZGeguoSsMw8gsBF .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-VZGeguoSsMw8gsBF .task{stroke-width:2}#mermaid-svg-VZGeguoSsMw8gsBF .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF .taskText:not([font-size]){font-size:11px}#mermaid-svg-VZGeguoSsMw8gsBF .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-VZGeguoSsMw8gsBF .task.clickable{cursor:pointer}#mermaid-svg-VZGeguoSsMw8gsBF .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-VZGeguoSsMw8gsBF .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-VZGeguoSsMw8gsBF .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-VZGeguoSsMw8gsBF .taskText0,#mermaid-svg-VZGeguoSsMw8gsBF .taskText1,#mermaid-svg-VZGeguoSsMw8gsBF .taskText2,#mermaid-svg-VZGeguoSsMw8gsBF .taskText3{fill:#fff}#mermaid-svg-VZGeguoSsMw8gsBF .task0,#mermaid-svg-VZGeguoSsMw8gsBF .task1,#mermaid-svg-VZGeguoSsMw8gsBF .task2,#mermaid-svg-VZGeguoSsMw8gsBF .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-VZGeguoSsMw8gsBF .taskTextOutside0,#mermaid-svg-VZGeguoSsMw8gsBF .taskTextOutside2{fill:#000}#mermaid-svg-VZGeguoSsMw8gsBF .taskTextOutside1,#mermaid-svg-VZGeguoSsMw8gsBF .taskTextOutside3{fill:#000}#mermaid-svg-VZGeguoSsMw8gsBF .active0,#mermaid-svg-VZGeguoSsMw8gsBF .active1,#mermaid-svg-VZGeguoSsMw8gsBF .active2,#mermaid-svg-VZGeguoSsMw8gsBF .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-VZGeguoSsMw8gsBF .activeText0,#mermaid-svg-VZGeguoSsMw8gsBF .activeText1,#mermaid-svg-VZGeguoSsMw8gsBF .activeText2,#mermaid-svg-VZGeguoSsMw8gsBF .activeText3{fill:#000 !important}#mermaid-svg-VZGeguoSsMw8gsBF .done0,#mermaid-svg-VZGeguoSsMw8gsBF .done1,#mermaid-svg-VZGeguoSsMw8gsBF .done2,#mermaid-svg-VZGeguoSsMw8gsBF .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-VZGeguoSsMw8gsBF .doneText0,#mermaid-svg-VZGeguoSsMw8gsBF .doneText1,#mermaid-svg-VZGeguoSsMw8gsBF .doneText2,#mermaid-svg-VZGeguoSsMw8gsBF .doneText3{fill:#000 !important}#mermaid-svg-VZGeguoSsMw8gsBF .crit0,#mermaid-svg-VZGeguoSsMw8gsBF .crit1,#mermaid-svg-VZGeguoSsMw8gsBF .crit2,#mermaid-svg-VZGeguoSsMw8gsBF .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-VZGeguoSsMw8gsBF .activeCrit0,#mermaid-svg-VZGeguoSsMw8gsBF .activeCrit1,#mermaid-svg-VZGeguoSsMw8gsBF .activeCrit2,#mermaid-svg-VZGeguoSsMw8gsBF .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-VZGeguoSsMw8gsBF .doneCrit0,#mermaid-svg-VZGeguoSsMw8gsBF .doneCrit1,#mermaid-svg-VZGeguoSsMw8gsBF .doneCrit2,#mermaid-svg-VZGeguoSsMw8gsBF .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-VZGeguoSsMw8gsBF .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-VZGeguoSsMw8gsBF .milestoneText{font-style:italic}#mermaid-svg-VZGeguoSsMw8gsBF .doneCritText0,#mermaid-svg-VZGeguoSsMw8gsBF .doneCritText1,#mermaid-svg-VZGeguoSsMw8gsBF .doneCritText2,#mermaid-svg-VZGeguoSsMw8gsBF .doneCritText3{fill:#000 !important}#mermaid-svg-VZGeguoSsMw8gsBF .activeCritText0,#mermaid-svg-VZGeguoSsMw8gsBF .activeCritText1,#mermaid-svg-VZGeguoSsMw8gsBF .activeCritText2,#mermaid-svg-VZGeguoSsMw8gsBF .activeCritText3{fill:#000 !important}#mermaid-svg-VZGeguoSsMw8gsBF .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-VZGeguoSsMw8gsBF g.classGroup text .title{font-weight:bolder}#mermaid-svg-VZGeguoSsMw8gsBF g.clickable{cursor:pointer}#mermaid-svg-VZGeguoSsMw8gsBF g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-VZGeguoSsMw8gsBF g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-VZGeguoSsMw8gsBF .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-VZGeguoSsMw8gsBF .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-VZGeguoSsMw8gsBF .dashed-line{stroke-dasharray:3}#mermaid-svg-VZGeguoSsMw8gsBF #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF .commit-id,#mermaid-svg-VZGeguoSsMw8gsBF .commit-msg,#mermaid-svg-VZGeguoSsMw8gsBF .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-VZGeguoSsMw8gsBF g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-VZGeguoSsMw8gsBF g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-VZGeguoSsMw8gsBF g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-VZGeguoSsMw8gsBF .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-VZGeguoSsMw8gsBF .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-VZGeguoSsMw8gsBF .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-VZGeguoSsMw8gsBF .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-VZGeguoSsMw8gsBF .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-VZGeguoSsMw8gsBF .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-VZGeguoSsMw8gsBF .edgeLabel text{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-VZGeguoSsMw8gsBF .node circle.state-start{fill:black;stroke:black}#mermaid-svg-VZGeguoSsMw8gsBF .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-VZGeguoSsMw8gsBF #statediagram-barbEnd{fill:#9370db}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-state .divider{stroke:#9370db}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-VZGeguoSsMw8gsBF .note-edge{stroke-dasharray:5}#mermaid-svg-VZGeguoSsMw8gsBF .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-VZGeguoSsMw8gsBF .error-icon{fill:#522}#mermaid-svg-VZGeguoSsMw8gsBF .error-text{fill:#522;stroke:#522}#mermaid-svg-VZGeguoSsMw8gsBF .edge-thickness-normal{stroke-width:2px}#mermaid-svg-VZGeguoSsMw8gsBF .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-VZGeguoSsMw8gsBF .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-VZGeguoSsMw8gsBF .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-VZGeguoSsMw8gsBF .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-VZGeguoSsMw8gsBF .marker{fill:#333}#mermaid-svg-VZGeguoSsMw8gsBF .marker.cross{stroke:#333}:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}#mermaid-svg-VZGeguoSsMw8gsBF {color: rgba(0, 0, 0, 0.75);font: ;}

char
unsigned/int
short
unsigned/long
double
float

C语言中的强制类型转换

前面说了自动转换,从这里开始聊聊强制类型转换,需要强制类型转换往往程序不那么智能了,需要人工进行干预。比如把一个int 类型的变量赋值给 char 类型的变量,或者说把两个 int 相乘时可能会得到一个很大的数,所以需要先把 int 强制转换成 double 计算防止溢出。

强制类型转换的格式为:(new_type_name) expression,其中 new_type_name 为新类型名称,expression为表达式。例如:


int val = 65535;
char ch = (char)val;

或者

int m = 2147483647, n = 100;
double result = (double)m * n;

无论是自动的类型转换还是强制类型转换,都只是为了本次操作或运算而进行的临时转换,转换的结果也会保存到临时的内存空间内,不会改变数据本来的类型或者具体的值。

有些强制类型转换是对原有数据的重新解释,比如:

void test(void* p)
{char* buffer = (char*)p;// ...
}

void* 类型的变量p,经过强制类型转换以后变成了char类型的指针,此后就可以把这段内存空间当成字符数组来处理了。

C++中的强制类型转换

在C++语言中新增了四个用于强制类型转换的关键字,分别是 static_castdynamic_cast, const_cast、 和 reinterpret_cast,使用语法为 xxxx_cast<new_type_name>(expression)

相比于C语言中使用小括号()来完成强制类型转换,C++中这几个关键字的引入能更清晰的表明它要完成强制类型转换的意图,容易暴露出隐藏的问题。

其实很长一段时间以来,我对于这四种强转方式区分的不是很清晰,其中 const_cast 的功能还比较容易辨别,但是另外3种经常混作一团,所以才有了这篇总结,而仔细学习后才发现,这4种强转关键字的区别就在他们的名字上,下面逐个来看一下。

static_cast

这个关键字的作用主要表现在 static 上,是一种静态的转换,在编译期就能确定的转换,可以完成C语言中的强制类型转换中的大部分工作,但需要注意的是,它不能转换掉表达式的 constvolitale 或者 __unaligned 属性。

它主要有以下几种用法:

  1. 用于基本数据类型之间的转换,如把int转换成char,把int转换成double等。
    int val = 110119;char c = static_cast<char>(val);double d = static_cast<double>(val);
  1. 将表达式转换成void类型,并将转换后的结果丢弃
    int val = 110119;static_cast<void>(val);
  1. 可以用于void* 和其他指针类类型之间的转换,但是不能用于两个无关指针类型的直接转换
   // 正常转换int *p = new int;void* p1 = static_cast<void*>(p);char* p2 =  static_cast<char*>(p1);// 编译失败 //error: invalid static_cast from type ‘int*’ to type ‘char*’char* p3 =  static_cast<char*>(p);
  1. 可以用于类继承结构中基类和派生类之间指针或引用的转换,向上转型安全,向下转型由于没有动态类型检查,是不安全的。
   struct B { };struct D : B { };D d;B& rb = d;D& rd = static_cast<D&>(rb);
  1. 如果涉及左值到右值、数组到指针或函数到指针的转换,也可以通过static_cast显式执行。
   template<typename _Tp>inline typename std::remove_reference<_Tp>::type&&move(_Tp&& __t){ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }

dynamic_cast

从名字上看,这个关键字与 static_cast 的静态转换是对立的,这是一个“动态”转换函数,只能对指针和引用的进行转换,并且只用于类继承结构中基类和派生类之间指针或引用的转换,可以进行向上、向下,或者横向的转换。

相比于 static_cast 的编译时转换, dynamic_cast 的转换还会在运行时进行类型检查,转换的条件也比较苛刻,必须有继承关系的类之间才能转换,并且在基类中有虚函数才可以,有一种特殊的情况就是可以把类指针转换成 void* 类型。

关于使用中的常见问题,参考以下几种情况:

  1. 普通类型的指针无法转换
   int val = 100;int *p = &val;// 编译失败 //error: cannot dynamic_cast ‘p’ (of type ‘int*’) to type ‘char*’ (target is not pointer or reference to class)char* pc =  dynamic_cast<char*>(p);
  1. 继承结构中基类里面没有虚函数无法转换
   struct B { };struct D : B { };D d;B* pb = &d;// 编译失败 //error: cannot dynamic_cast ‘pb’ (of type ‘struct test1()::B*’) to type ‘struct test1()::D*’ (source type is not polymorphic)D* pd = dynamic_cast<D*>(pb)
  1. 指针或引用转换的类型不是正确的类型,如果参数类型是指针会返回目标类型空指针,如果参数类型是引用则会抛出 std::bad_cast 异常。
   struct B { virtual void test() {} };struct D : B { };B d;B* pb = &d;D* pd = dynamic_cast<D*>(pb);// 编译成功,但是pb指针指向的类型是 B,向下转型失败,输出结果是0,也就是空指针std::cout << pd << std::endl;
  1. 一个正常转换的例子,包含向上、向下、横向转换
   struct B { virtual void test() {} };struct D1 : virtual B { };struct D2 : virtual B { };struct MD : D1, D2 { };D1* pd1 = new MD();std::cout << pd1 << std::endl;// 向上转型B* pb = dynamic_cast<B*>(pd1);std::cout << pb << std::endl;// 向下转型MD* pmd = dynamic_cast<MD*>(pd1);std::cout << pmd << std::endl;// 横向转型D2* pd2 = dynamic_cast<D2*>(pd1);std::cout << pd2 << std::endl;

运行结果如下,在横向转换时指针发生了变化,可以看出 dynamic_cast 不是简单的数据强转,还进行了指针的偏移:

albert@home-pc:/mnt/d/testconvert$ g++ cppconvert.cpp
albert@home-pc:/mnt/d/testconvert$ ./a.out
0x15c0c40
0x15c0c40
0x15c0c40
0x15c0c48

const_cast

在C/C++中,const限定符通常被用来限定变量,用于表示该变量的值不能被修改,这种限定可以避免程序员犯一些初级错误,但同时也造成了一些不便,比如一些已有函数要求非常量指针,但是掉用这些函数的接口函数中都传递了常量指针,这时候就要对指针类型去常量化。

但需要特别注意的是 const_cast 不能去除变量的常量性,只能用来去除指向常数对象的指针或引用的常量性,且去除常量性的对象必须为指针或引用。

常量指针被转化成非常量指针,并且仍然指向原来的对象,常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象可能被转换成非常量对象。

  1. 尝试去除非指针和引用的类型的常量性会编译失败
   const int i = 6;// 编译错误 //int j = const_cast<int>(i);
  1. 企图用一个指针来修改常量:
    const int val = 6;//编译错误 //error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]int* cp = &val;
  1. 修改一个指针的常量性:
   const int val = 6;std::cout << "&val=" << &val << ", val=" << val << std::endl;const int* cp = &val;int *p = const_cast<int*>(cp);*p = 2;std::cout << "&val=" << &val << ", val=" << val << std::endl;std::cout << "p=" << p << ", *p=" << *p << std::endl;

运行结果如下:

&val=0x7ffff7446bd4, val=6
&val=0x7ffff7446bd4, val=6
p=0x7ffff7446bd4, *p=2

运行之后,变量 p 指向了变量val地址,并改变了地址所指向的内存数据,但是打印 val 的值并没有发生变化,这是因为 val 作为常量在编译期使用它的地方就进行了替换,接下来再看另一种情况。

   int init = 6;const int val = init;std::cout << "&val=" << &val << ", val=" << val << std::endl;const int* cp = &val;int *p = const_cast<int*>(cp);*p = 2;std::cout << "&val=" << &val << ", val=" << val << std::endl;std::cout << "p=" << p << ", *p=" << *p << std::endl;

代码逻辑不变,只在开始的位置使用 init 这个变量来代替 6 这个常数,运行结果如下:

val=0x7fffe8c71fa0, val=6
&val=0x7fffe8c71fa0, val=2
p=0x7fffe8c71fa0, *p=2

运行之后 val 本身的变化也应用到了使用它的地方,这里的编译器替换已经不起作用了。

实际上,使用const_cast通常是一种无奈之举,利用const_cast去掉指针或引用的常量性并且去修改原始变量的数值,这是一种非常不好的行为,如果可以的话,尽可能在程序设计阶段就规避这种情况。

reinterpret_cast

它被用于不同类型指针或引用之间的转换,或者指针和整数之间的转换,是对比特位的简单拷贝并重新解释,因此在使用过程中需要特别谨慎,比如前面提到的一个例子,static_cast 不能将 int* 直接强转成 char*,使用reinterpret_cast就可以办到。

  1. 不同基础类型指针类型之间转换:
   int *p = new int;// 编译失败 //error: invalid static_cast from type ‘int*’ to type ‘char*’char* p1 =  static_cast<char*>(p);// 编译成功char* p2 =  reinterpret_cast<char*>(p1);
  1. 基础类型指针与类对象指针之间的转换:
   struct B { int val;};B b{100};std::cout << "b.val=" << b.val << std::endl;int* p = reinterpret_cast<int*>(&b);std::cout << "*p=" << *p << std::endl;

运行之后可以得到 *p 的值为100,也就是重新解释了变量 b 的地址为整型指针。

  1. 将地址值转换成整数
   struct B { int val;};B b{101};std::cout << "&b=" << &b << std::endl;long addr = reinterpret_cast<long>(&b);std::cout << "addr=" << addr << std::endl;

运行结果如下:

&b=0x7ffffdc4f270
addr=140737450930800

这里的地址 0x7ffffdc4f270 被解释成了整数 140737450930800,因为涉及到字节序,这也是很多文章提到的 reinterpret_cast 不具备一致性的问题,我们需要知道这一个点,只要代码不依赖主机字节序就没有问题。

强转关键字的选择

好几个关键字,并且有些功能还是重复的,那么究竟该选哪一个呢?这个真得按照经验来选,我建议使用排除法,按照 const_cast -> dynamic_cast -> reinterpret_cast -> static_cast 的顺序带入选择。

  1. 先看是不是要去掉指针或引用的常量属性,如果是只能选择 const_cast

  2. 再看转换的是不是继承体系下的多态结构,如果是这种结构下的指针和引用的转换最好使用 dynamic_cast

  3. 接着看是不是偏底层的代码,需要将无关类型指针进行转换,或者指针与整数之间进行转换,如果是则选择 reinterpret_cast

  4. 前三种情况都不满足,那就只能使用 static_cast

总结

  • C/C++中不同数据类型进行运算或者赋值的时候会发生数据转换,这种转换有些是自动进行的,有些需要进行显示的强制类型转换
  • 在C语言中强制类型转换写成(new_type_name) expression的形式,new_type_name 是要转换的目标类型,expression 是待转换的表达式
  • 在C++中强制类型转换通过更明显的关键字来完成,分别是static_castdynamic_cast, const_cast、 和 reinterpret_cast
  • static_cast 是静态转换,在编译期完成完成转换,与C语言中的强制类型转换重合度最高
  • dynamic_cast 是动态转换,在运行时转换会进行检查,必须用在有继承关系的多态结构中
  • const_cast 是常量转换,用于取出指针或引用的常量属性,但是尽量通过设计杜绝它的使用场景
  • reinterpret_cast 是一种内存数据的重新解释,比较原始,开发者使用它的时候应该明确的知道自己在做什么

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==


今夜的雨,好美~

C/C++中的数据类型转换()/static_cast/dynamic_cast/const_cast/reinterpret_cast相关推荐

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

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

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

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

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

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

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

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

  5. static_cast, dynamic_cast, const_cast,reinterpret_cast探讨

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

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

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

  7. c++类型转换:static_cast, dynamic_cast,const_cast和reinterpret_cast

    static_cast 用法:static_cast < type-id > ( expression ) 说明:该运算符把expression转换为type-id类型,但没有运行时类型检 ...

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

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

  9. C/C++中的数据类型转换

    文章目录 1 隐式类型转换 1.1 隐式类型转换的基本概念 1.2 隐式类型转换的发生点 1.3 浮点数赋值给整形数分析 2 C语言中的强制类型转换 3 C++中的强制类型转换 3.1 static_ ...

最新文章

  1. 【C语言入门教程】3.4 循环控制语句
  2. myeclipse2014 mysql连接池_myeclips配置mysql连接池
  3. 【Groovy】编译时元编程 ( 编译时方法注入 | 使用 buildFromSpec、buildFromString、buildFromCode 进行方法注入 )
  4. 1.5 测试php解析
  5. ElementUI中el-upload中怎样限制上传文件的格式
  6. cuda linux编译器_CUDA与Linux系统
  7. linux中tr命令的用法
  8. 左神算法:判断 t1 树中是否有与 t2 树拓扑结构完全相同的子树(Java版)
  9. python通过tkinter界面库实现三角形成立的测试
  10. 剪了 20% 的刘海、120Hz 刷新率、1TB 存储,iPhone 13 来了!
  11. Web 服务器远程控制硬件(Arduino)
  12. (转)C# 与Rust :知识库
  13. android ble 写失败,Android低功耗蓝牙BLE写入数据很大几率会失败 求解
  14. 二级倒立摆的建模、线性化S函数的PID控制以及非线性化S函数的PID控制
  15. 计算机组成原理--复习简答题+答案
  16. 阿里云产品之基于OSS快速搭建Web网站
  17. 北京大学王悦博士给学生的话
  18. @guardedby同步注解
  19. My Visual DataBase(数据库编程软件)v5.3免费版
  20. 谷歌云端硬盘 转存_如何在Mac上设置和使用Google云端硬盘

热门文章

  1. vue+element-ui 动态加载本地图片
  2. IOS7 隐藏状态栏 (电池栏)
  3. 卷积层运算详解与im2col实现
  4. PIM-SM中DR作用
  5. java 将Object类型转换为long
  6. 心态-《不抱怨的世界》书中的精髓:通过4个步骤,成为一个不抱怨、每天都快乐的人。
  7. 听见丨HTC推国行VR一体机VIVE Focus:搭载骁龙835+AMOLED屏 Embark开始测试用无人驾驶卡车运送冰箱
  8. android如何查看分区信息,【Android】Android如何查看分区情况
  9. Linux学习笔记:DNS
  10. Chapter 9 Measurement Bias