293 lines
22 KiB
HTML
293 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh" dir="ltr" class="client-nojs" xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
|
|
<head><meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>显式类型转换</title>
|
|
<link rel="stylesheet" href="ext.css" />
|
|
<link rel="stylesheet" href="site_modules.css" />
|
|
</head>
|
|
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-cpp_language_explicit_cast skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">显式类型转换</h1>
|
|
<div id="bodyContent">
|
|
<div id="contentSub"><span class="subpages">< <a href="cpp.html">cpp</a>‎ | <a href="cpp-language.html">language</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<p>用显式和隐式转换的组合进行类型之间的转换。</p>
|
|
<h3><span class="mw-headline" id=".E8.AF.AD.E6.B3.95">语法</span></h3>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>(</b></code> <span class="t-spar">新类型</span> <code><b>)</b></code> <span class="t-spar">表达式</span></td>
|
|
<td>(1)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">新类型</span> <code><b>(</b></code> <span class="t-spar">表达式</span> <code><b>)</b></code></td>
|
|
<td>(2)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">新类型</span> <code><b>(</b></code> <span class="t-spar">表达式列表</span> <code><b>)</b></code></td>
|
|
<td>(3)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">新类型</span> <code><b>(</b></code> <code><b>)</b></code></td>
|
|
<td>(4)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">新类型</span> <code><b>{</b></code> <span class="t-spar">表达式列表</span><span class="t-mark">(可选)</span> <code><b>}</b></code></td>
|
|
<td>(5)</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">模板名</span> <code><b>(</b></code> <span class="t-spar">表达式列表</span><span class="t-mark">(可选)</span> <code><b>)</b></code></td>
|
|
<td>(6)</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><span class="t-spar">模板名</span> <code><b>{</b></code> <span class="t-spar">表达式列表</span><span class="t-mark">(可选)</span> <code><b>}</b></code></td>
|
|
<td>(7)</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>auto</b></code> <code><b>(</b></code> <span class="t-spar">表达式</span> <code><b>)</b></code></td>
|
|
<td>(8)</td>
|
|
<td><span class="t-mark-rev t-since-cxx23">(C++23 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>auto</b></code> <code><b>{</b></code> <span class="t-spar">表达式</span> <code><b>}</b></code></td>
|
|
<td>(9)</td>
|
|
<td><span class="t-mark-rev t-since-cxx23">(C++23 起)</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<p>返回 <span class="t-spar">新类型</span> 类型的值。</p>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<div class="t-li1"><span class="t-li">1)</span> 遇到 <i>C 风格转型表达式</i>时,编译器尝试将它解释成下列转型表达式,以此顺序:</div>
|
|
<div class="t-li2"><span class="t-li">a)</span> <span class="t-c"><code><a href="cpp-language-const_cast.html">const_cast</a></code><span class="mw-geshi cpp source-cpp"><span class="sy1"><</span>新类型<span class="sy1">></span><span class="br0">(</span>表达式<span class="br0">)</span></span></span>;</div>
|
|
<div class="t-li2"><span class="t-li">b)</span> <span class="t-c"><code><a href="cpp-language-static_cast.html">static_cast</a></code><span class="mw-geshi cpp source-cpp"><span class="sy1"><</span>新类型<span class="sy1">></span><span class="br0">(</span>表达式<span class="br0">)</span></span></span>,带扩展:额外允许将到<a href="cpp-language-derived_class.html">派生类</a>的指针或引用转型成到无歧义基类的指针或引用(反之亦然),纵使基类<a href="cpp-language-access.html">不可访问</a>也是如此(即此转型忽略 private 继承说明符)。同样适用于将<a href="cpp-language-pointer.html">成员指针</a>转型为指向无歧义非虚基类的成员的指针;</div>
|
|
<div class="t-li2"><span class="t-li">c)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span></span></span>(带扩展)后随 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">const_cast</span></span></span>;</div>
|
|
<div class="t-li2"><span class="t-li">d)</span> <span class="t-c"><code><a href="cpp-language-reinterpret_cast.html">reinterpret_cast</a></code><span class="mw-geshi cpp source-cpp"><span class="sy1"><</span>新类型<span class="sy1">></span><span class="br0">(</span>表达式<span class="br0">)</span></span></span>;</div>
|
|
<div class="t-li2"><span class="t-li">e)</span> <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">reinterpret_cast</span></span></span> 后随 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">const_cast</span></span></span>。</div>
|
|
<div class="t-li1"><span class="t-li"></span> 选择首个满足相应转型运算符要求的方式,即便它无法编译(见示例)。若转型能解释成多于一种 <code>static_cast</code> 后随 <code>const_cast</code> 的方式,则它无法编译。</div>
|
|
<div class="t-li1"><span class="t-li"></span> 另外,C 风格转型写法允许在不完整类型的指针之间进行双向转型。若 <span class="t-spar">表达式</span> 与 <span class="t-spar">新类型</span> 是指向不完整类型的指针,则选用 <code>static_cast</code> 还是 <code>reinterpret_cast</code> 是未指明的。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> <i>函数式转型表达式</i>由一个简单类型说明符或一个 typedef 说明符构成(换言之,它是单个单词的类型名:<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">int</span><span class="br0">(</span>表达式<span class="br0">)</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span><span class="sy2">*</span><span class="br0">(</span>表达式<span class="br0">)</span></span></span> 非法),后随带括号的单个表达式。此转型表达式准确等价于对应的 C 风格转型表达式。</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 若括号中有多于一个表达式,则 <span class="t-spar">新类型</span> 必须是带有适当声明的<a href="cpp-language-initializer_list.html" class="mw-redirect">构造函数</a>的类。此表达式是 <span class="t-spar">新类型</span> 类型的纯右值,<span class="t-rev-inl t-until-cxx17"><span>其指代的临时量</span> <span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span><span class="t-rev-inl t-since-cxx17"><span>其结果对象</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>以 <span class="t-spar">表达式列表</span> <a href="cpp-language-direct_initialization.html">直接初始化</a>。</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 若 <span class="t-spar">新类型</span> 指名一个非数组完整对象类型,则此表达式是 <span class="t-spar">新类型</span> 类型的纯右值,<span class="t-rev-inl t-until-cxx17"><span>指代该类型临时量</span> <span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span><span class="t-rev-inl t-since-cxx17"><span>其结果对象为该类型(可能添加 cv 限定符)</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>。若 <span class="t-spar">新类型</span> 是对象类型,则对象被<a href="cpp-language-value_initialization.html">值初始化</a>。若 <span class="t-spar">新类型</span> 是(可<a href="cpp-language-cv.html">有 cv 限定的</a>)<code>void</code>,则表达式是 void 纯右值<span class="t-rev-inl t-since-cxx17"><span>而无结果对象</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>。</div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 单个单词的类型名后随<i>花括号初始化器列表</i>,是指定类型的纯右值,<span class="t-rev-inl t-until-cxx17"><span>其指代的临时量</span> <span><span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span><span class="t-rev-inl t-since-cxx17"><span>其结果对象</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>以指定的<i>花括号初始化器列表</i><a href="cpp-language-list_initialization.html">直接列表初始化</a>。若 <span class="t-spar">新类型</span> 是(可<a href="cpp-language-cv.html">有 cv 限定的</a>)<code>void</code>,则表达式是 void 纯右值<span class="t-rev-inl t-since-cxx17"><span>而无结果对象</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>。<span class="t-rev-inl"><span>这是仅有的能创建<a href="cpp-language-array.html#.E6.95.B0.E7.BB.84.E5.8F.B3.E5.80.BC">数组纯右值</a>的表达式。</span> <span></span></span></div>
|
|
<div class="t-li1"><span class="t-li">6,7)</span> 同 <span class="t-v">(2-5)</span>,但首先进行<a href="cpp-language-class_template_argument_deduction.html">类模板实参推导</a>。</div>
|
|
<div class="t-li1"><span class="t-li">8,9)</span> <a href="cpp-language-auto.html"><code>auto</code></a> 说明符被分别替换成以 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">auto</span> x<span class="br0">(</span>expr<span class="br0">)</span><span class="sy4">;</span></span></span> (决不转译成函数声明)或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">auto</span> x<span class="br0">{</span>expr<span class="br0">}</span><span class="sy4">;</span></span></span> 声明的变量 <code>x</code> 的被推导类型。结果始终为对象类型的纯右值。</div>
|
|
<p>同所有转型表达式,结果是:</p>
|
|
<ul>
|
|
<li>左值,如果 <span class="t-spar">新类型</span> 是左值引用或到函数类型的右值引用;</li>
|
|
<li>亡值,如果 <span class="t-spar">新类型</span> 是到对象类型的右值引用;</li>
|
|
<li>否则为纯右值。</li>
|
|
</ul>
|
|
<h3><span class="mw-headline" id=".E7.A4.BA.E4.BE.8B">示例</span></h3>
|
|
<div class="t-example">
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">double</span> f <span class="sy1">=</span> <span class="nu16">3.14</span><span class="sy4">;</span>
|
|
<span class="kw4">unsigned</span> <span class="kw4">int</span> n1 <span class="sy1">=</span> <span class="br0">(</span><span class="kw4">unsigned</span> <span class="kw4">int</span><span class="br0">)</span>f<span class="sy4">;</span> <span class="co1">// C 风格转型</span>
|
|
<span class="kw4">unsigned</span> <span class="kw4">int</span> n2 <span class="sy1">=</span> <span class="kw4">unsigned</span><span class="br0">(</span>f<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 函数式转型</span>
|
|
|
|
<span class="kw1">class</span> C1<span class="sy4">;</span>
|
|
<span class="kw1">class</span> C2<span class="sy4">;</span>
|
|
C2<span class="sy2">*</span> foo<span class="br0">(</span>C1<span class="sy2">*</span> p<span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">return</span> <span class="br0">(</span>C2<span class="sy2">*</span><span class="br0">)</span>p<span class="sy4">;</span> <span class="co1">// 转型不完整类型到不完整类型</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="co1">// 此示例中,C 风格转型被转译成 static_cast</span>
|
|
<span class="co1">// 尽管它的作用也可与 reinterpret_cast 一致</span>
|
|
<span class="kw1">struct</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> I1 <span class="sy4">:</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> I2 <span class="sy4">:</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> D <span class="sy4">:</span> I1, I2 <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
D<span class="sy2">*</span> d <span class="sy1">=</span> nullptr<span class="sy4">;</span>
|
|
<span class="co1">// A* a = (A*)d; // 编译时错误</span>
|
|
A<span class="sy2">*</span> a <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span>A<span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span>d<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 可以编译</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.BC.95.E7.94.A8">引用</span></h3>
|
|
<div class="t-ref-std-c++20">
|
|
<ul>
|
|
<li>C++20 标准(ISO/IEC 14882:2020):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>7.6.1.4 Explicit type conversion (functional notation) [expr.type.conv]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>7.6.3 Explicit type conversion (cast notation) [expr.cast]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c++17">
|
|
<ul>
|
|
<li>C++17 标准(ISO/IEC 14882:2017):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>8.2.3 Explicit type conversion (functional notation) [expr.type.conv]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>8.4 Explicit type conversion (cast notation) [expr.cast]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c++14">
|
|
<ul>
|
|
<li>C++14 标准(ISO/IEC 14882:2014):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>5.2.3 Explicit type conversion (functional notation) [expr.type.conv]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>5.4 Explicit type conversion (cast notation) [expr.cast]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c++11">
|
|
<ul>
|
|
<li>C++11 标准(ISO/IEC 14882:2011):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>5.2.3 Explicit type conversion (functional notation) [expr.type.conv]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>5.4 Explicit type conversion (cast notation) [expr.cast]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c++03">
|
|
<ul>
|
|
<li>C++03 标准(ISO/IEC 14882:2003):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>5.2.3 Explicit type conversion (functional notation) [expr.type.conv]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>5.4 Explicit type conversion (cast notation) [expr.cast]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c++98">
|
|
<ul>
|
|
<li>C++98 标准(ISO/IEC 14882:1998):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>5.2.3 Explicit type conversion (functional notation) [expr.type.conv]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>5.4 Explicit type conversion (cast notation) [expr.cast]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<table class="t-dsc-begin">
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-const_cast.html">const_cast 转换</a></td>
|
|
<td>添加或移除 const</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-static_cast.html">static_cast 转换</a></td>
|
|
<td>进行基本转换</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-dynamic_cast.html">dynamic_cast 转换</a></td>
|
|
<td>进行有检查的多态转换</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-reinterpret_cast.html">reinterpret_cast 转换</a></td>
|
|
<td>进行通用低层转换</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-implicit_conversion.html">标准转换</a></td>
|
|
<td>从一个类型到另一类型的隐式转换</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|