371 lines
40 KiB
HTML
371 lines
40 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_data_members 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>非静态数据成员是在类的<a href="cpp-language-class.html">成员说明</a>中声明的。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">class</span> S
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> n<span class="sy4">;</span> <span class="co1">// 非静态数据成员</span>
|
|
<span class="kw4">int</span><span class="sy3">&</span> r<span class="sy4">;</span> <span class="co1">// 引用类型的非静态数据成员</span>
|
|
<span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">1</span>, <span class="nu0">2</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 带默认成员初始化器的非静态数据成员(C++11)</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s, <span class="sy2">*</span>ps<span class="sy4">;</span> <span class="co1">// 两个非静态数据成员</span>
|
|
<span class="kw1">struct</span> NestedS
|
|
<span class="br0">{</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s<span class="sy4">;</span>
|
|
<span class="br0">}</span> d5<span class="sy4">;</span> <span class="co1">// 具有嵌套类型的非静态数据成员</span>
|
|
<span class="kw4">char</span> bit <span class="sy4">:</span> <span class="nu0">2</span><span class="sy4">;</span> <span class="co1">// 2 位的位域</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>允许任意<a href="cpp-language-declarations.html">简单声明</a>,但</p>
|
|
<ul>
|
|
<li>不允许使用 <a href="cpp-keyword-extern.html"><tt>extern</tt></a> 和 <a href="cpp-keyword-register.html"><tt>register</tt></a> 存储类说明符;</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li>不允许使用 <a href="cpp-keyword-thread_local.html"><tt>thread_local</tt></a> 存储类说明符(但<a href="cpp-language-static.html">静态</a>数据成员可以使用);</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<ul>
|
|
<li>不允许<a href="cpp-language-type.html#.E4.B8.8D.E5.AE.8C.E6.95.B4.E7.B1.BB.E5.9E.8B">不完整类型</a>、<a href="cpp-language-abstract_class.html">抽象类类型</a>及其数组:通常,类 <code>C</code> 不能拥有 <code>C</code> 类型的非静态数据成员,尽管它能拥有 <code>C&</code>(C 的引用)或 <code>C*</code>(C 的指针)类型的非静态数据成员;</li>
|
|
<li>当存在至少一个用户定义的构造函数时,非静态数据成员不能拥有与类名相同的名字;</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li><a href="cpp-language-auto.html"><code>auto</code> 说明符</a>不能用于非静态数据成员的声明(尽管<a href="cpp-language-static.html#.E5.B8.B8.E9.87.8F.E9.9D.99.E6.80.81.E6.88.90.E5.91.98">在类定义中初始化</a>的静态数据成员可以使用)。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>另外,允许<a href="cpp-language-bit_field.html">位域声明</a>。</p>
|
|
<h3><span class="mw-headline" id=".E5.B8.83.E5.B1.80">布局</span></h3>
|
|
<p>当创建某个类 <code>C</code> 的对象时,每个非引用类型的非静态数据成员都在 <code>C</code> 的对象表示的某个部分中分配。引用是否占据存储是由实现定义的,但它们的<a href="cpp-language-storage_duration.html">存储期</a>与以它们作为成员的对象相同。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx23">
|
|
<td>
|
|
<p>对于非<a href="cpp-language-union.html">联合体</a>类类型,<span class="t-rev-inl t-since-cxx20"><span><a href="cpp-language-object.html#.E5.AD.90.E5.AF.B9.E8.B1.A1">非零大小</a>的</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span><span class="t-rev-inl t-until-cxx11"><span>未被<a href="cpp-language-access.html">访问说明符</a>分隔</span> <span><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></span></span><span class="t-rev-inl t-since-cxx11"><span>拥有相同<a href="cpp-language-access.html">成员访问</a></span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>的成员,始终按照较后声明的成员在类对象中拥有较高地址的方式分配。<span class="t-rev-inl t-until-cxx11"><span>被访问说明符分隔</span> <span><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></span></span><span class="t-rev-inl t-since-cxx11"><span>拥有不同访问控制</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>的成员以未指明的顺序分配(编译器可以将它们组合在一起)。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx23">(C++23 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx23">
|
|
<td>
|
|
<p>对于非<a href="cpp-language-union.html">联合体</a>类类型,<a href="cpp-language-object.html#.E5.AD.90.E5.AF.B9.E8.B1.A1">非零大小</a>的成员始终按照较后声明的成员在类对象中拥有较高地址的方式分配。注意成员的访问控制仍然影响标准布局属性(见后述)。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx23">(C++23 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>对齐要求可能需要在成员间,或在类的最后成员之后进行填充。</p>
|
|
<h3><span class="mw-headline" id=".E6.A0.87.E5.87.86.E5.B8.83.E5.B1.80">标准布局</span></h3>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx11">
|
|
<td>
|
|
<p>一个类只有在它是<a href="cpp-named_req-PODType.html"><span style="font-style:italic">简旧数据类型</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(PODType)</span></a> 的情况下是标准布局(standard-layout)的并拥有下述属性。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx11">(C++11 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<p>所有非静态数据成员均拥有相同访问控制,且满足其他特定条件的类被称作<i>标准布局(standard-layout)类型</i>(对其规定的列表见<a href="cpp-named_req-StandardLayoutType.html"><span style="font-style:italic">标准布局类型</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(StandardLayoutType)</span></a> )。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>两个标准布局非联合类类型可以拥有非静态数据成员和位域的<i>共同起始序列</i>,它是一个或多个起始成员(按声明顺序)的序列,条件是这些成员拥有布局兼容的类型<span class="t-rev-inl t-since-cxx20"><span>,均声明有 <code>[[<a href="cpp-language-attributes-no_unique_address.html">no_unique_address</a>]]</code> 属性或无该属性</span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>,且当它们是位域时拥有相同宽度。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A <span class="br0">{</span> <span class="kw4">int</span> a<span class="sy4">;</span> <span class="kw4">char</span> b<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> B <span class="br0">{</span> <span class="kw4">const</span> <span class="kw4">int</span> b1<span class="sy4">;</span> <span class="kw4">volatile</span> <span class="kw4">char</span> b2<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// A 与 B 的共同起始序列是 A.a, A.b 与 B.b1, B.b2</span>
|
|
<span class="kw1">struct</span> C <span class="br0">{</span> <span class="kw4">int</span> c<span class="sy4">;</span> <span class="kw4">unsigned</span> <span class="sy4">:</span> <span class="nu0">0</span><span class="sy4">;</span> <span class="kw4">char</span> b<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// A 与 C 的共同起始序列是 A.a 与 C.c</span>
|
|
<span class="kw1">struct</span> D <span class="br0">{</span> <span class="kw4">int</span> d<span class="sy4">;</span> <span class="kw4">char</span> b <span class="sy4">:</span> <span class="nu0">4</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// A 与 D 的共同起始序列是 A.a 与 D.d</span>
|
|
<span class="kw1">struct</span> E <span class="br0">{</span> <span class="kw4">unsigned</span> <span class="kw4">int</span> e<span class="sy4">;</span> <span class="kw4">char</span> b<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// A 与 E 的共同起始序列为空</span></pre></div>
|
|
</div>
|
|
<p>如果两个标准布局非联合类类型具有同一类型(如果存在 cv 限定符则忽略),或是布局兼容的<a href="cpp-language-enum.html">枚举</a>(即拥有相同底层类型的枚举类型),或它们的'共同起始序列<i>由它们所有的非静态数据成员和位域组成,那么称它们</i>布局兼容(layout compatible)<i>(上例中,<code>A</code> 与 <code>B</code> 布局兼容)</i></p>
|
|
<p>如果两个标准布局联合体类型拥有相同数量的非静态数据成员,且(以任何顺序)对应的非静态数据成员拥有布局兼容的类型,那么称它们<i>布局兼容</i>。</p>
|
|
<p>标准布局类型拥有以下特殊性质:</p>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>在以非联合类类型 <code>T1</code> 作为活跃成员的标准布局联合体中,容许读取具有非联合类类型 <code>T2</code> 的另一联合体成员的非静态数据成员 <code>m</code>,只要 <code>m</code> 是 <code>T1</code> 与 <code>T2</code> 的共同起始序列的一部分(但通过非 volatile 泛左值读取 volatile 成员是未定义的)。</li>
|
|
<li>指向标准布局类类型的指针可以被 <a href="cpp-language-reinterpret_cast.html"><code>reinterpret_cast</code></a> 成指向其首个非静态非位域数据成员的指针(如果它拥有非静态数据成员)<span class="t-rev-inl t-since-cxx11"><span>,或指向其任何基类子对象的指针(如果有基类)</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>,反之亦然。换言之,不允许标准布局类型的首个数据成员前有填充。注意<a href="cpp-language-reinterpret_cast.html#.E7.B1.BB.E5.9E.8B.E5.88.AB.E5.90.8D.E5.8C.96">严格别名化</a>规则仍然适用于这种转型的结果。</li>
|
|
<li>宏 <span class="t-lc"><a href="cpp-types-offsetof.html">offsetof</a></span> 可以用于确定任何成员距标准布局类起始的偏移量。</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
<h3><span class="mw-headline" id=".E6.88.90.E5.91.98.E5.88.9D.E5.A7.8B.E5.8C.96">成员初始化</span></h3>
|
|
<p>非静态数据成员可以用下列两种方式之一初始化:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 在构造函数的<a href="cpp-language-initializer_list.html" class="mw-redirect">成员初始化器列表</a>中。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> S
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> n<span class="sy4">;</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s<span class="sy4">;</span>
|
|
S<span class="br0">(</span><span class="br0">)</span> <span class="sy4">:</span> n<span class="br0">(</span><span class="nu0">7</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// 直接初始化 n,默认初始化 s</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<div class="t-li1"><span class="t-li">2)</span> 通过<i>默认成员初始化器</i>,它是成员声明中包含的花括号或等号<a href="cpp-language-initialization.html">初始化器</a>,并在成员初始化器列表中忽略该成员的情况下得到使用。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> S
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">7</span><span class="sy4">;</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> s<span class="br0">{</span><span class="st0">'a'</span>, <span class="st0">'b'</span>, <span class="st0">'c'</span><span class="br0">}</span><span class="sy4">;</span>
|
|
S<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// 默认成员初始化器将复制初始化 n,列表初始化 s</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<p>如果成员拥有默认成员初始化器,并且在构造函数的成员初始化器列表中也有出现,那么对该构造函数忽略默认成员初始化器。</p>
|
|
<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="co2">#include <iostream></span>
|
|
|
|
<span class="kw4">int</span> x <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> S
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> n <span class="sy1">=</span> <span class="sy2">++</span>x<span class="sy4">;</span>
|
|
S<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// 使用默认成员初始化器</span>
|
|
S<span class="br0">(</span><span class="kw4">int</span> arg<span class="br0">)</span> <span class="sy4">:</span> n<span class="br0">(</span>arg<span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// 使用成员初始化器</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>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> x <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// 打印 0</span>
|
|
S s1<span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> x <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// 打印 1(运行默认初始化器)</span>
|
|
S s2<span class="br0">(</span><span class="nu0">7</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> x <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// 打印 1(未运行默认初始化器)</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>输出:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="text source-text">
|
|
<pre class="de1">0
|
|
1
|
|
1</pre></div>
|
|
</div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<p>不能对<a href="cpp-language-bit_field.html">位域</a>成员使用默认成员初始化器。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>数组类型成员不能从成员初始化器推导其大小:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> X
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> a<span class="br0">[</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 错误</span>
|
|
<span class="kw4">int</span> b<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>默认成员初始化器不允许导致外围类的预置<a href="cpp-language-default_constructor.html">默认构造函数</a>的隐式定义,或该构造函数的异常说明:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> node
|
|
<span class="br0">{</span>
|
|
node<span class="sy2">*</span> p <span class="sy1">=</span> new node<span class="sy4">;</span> <span class="co1">// 错误:使用隐式或预置的 node::node() </span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>在默认成员初始化器中,引用成员不能绑定到临时量(注意,<a href="cpp-language-initializer_list.html#.E8.A7.A3.E9.87.8A" class="mw-redirect">成员初始化器列表</a>有同样的规则)</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A
|
|
<span class="br0">{</span>
|
|
A<span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">default</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
A<span class="br0">(</span><span class="kw4">int</span> v<span class="br0">)</span> <span class="sy4">:</span> v<span class="br0">(</span>v<span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="co1">// OK</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&</span> v <span class="sy1">=</span> <span class="nu0">42</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
A a1<span class="sy4">;</span> <span class="co1">// 错误:临时量到引用的非良构绑定</span>
|
|
A a2<span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK(忽略默认成员初始化器,因为 v 在构造函数中出现)</span>
|
|
<span class="co1">// 然而 a2.v 是悬垂引用</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx14">
|
|
<td>
|
|
<p>如果默认成员初始化器拥有会执行聚合初始化并会使用同一初始化器的子表达式,那么产生错误:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> A<span class="sy4">;</span>
|
|
<span class="kw4">extern</span> A a<span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> A
|
|
<span class="br0">{</span>
|
|
<span class="kw4">const</span> A<span class="sy3">&</span> a1<span class="br0">{</span>A<span class="br0">{</span>a, a<span class="br0">}</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
<span class="kw4">const</span> A<span class="sy3">&</span> a2<span class="br0">{</span>A<span class="br0">{</span><span class="br0">}</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 错误</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
A a<span class="br0">{</span>a, a<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx14">(C++14 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E7.94.A8.E6.B3.95">用法</span></h3>
|
|
<p>非静态数据成员或非静态成员函数的名字只能出现在下列三种情形中:</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 作为类成员访问表达式的一部分,其中的类要么拥有此成员,要么从拥有此成员的类派生,这包括在任何允许 <a href="cpp-language-this.html">this</a> 的语境(成员函数体内,成员初始化器列表内,类内默认成员初始化器内)中使用非静态成员的名字时所出现的隐式 <code>this-></code> 成员访问表达式。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> S
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> m<span class="sy4">;</span>
|
|
<span class="kw4">int</span> n<span class="sy4">;</span>
|
|
<span class="kw4">int</span> x <span class="sy1">=</span> m<span class="sy4">;</span> <span class="co1">// OK:在默认初始化器中允许隐式的 this-> (C++11)</span>
|
|
S<span class="br0">(</span><span class="kw4">int</span> i<span class="br0">)</span> <span class="sy4">:</span> m<span class="br0">(</span>i<span class="br0">)</span>, n<span class="br0">(</span>m<span class="br0">)</span> <span class="co1">// OK:在成员初始化器列表中允许隐式的 this-> </span>
|
|
<span class="br0">{</span>
|
|
this<span class="sy2">-</span><span class="sy1">></span>f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 显式的成员访问表达式</span>
|
|
f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 在成员函数体内允许隐式的 this-></span>
|
|
<span class="br0">}</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 构成<a href="cpp-language-pointer.html">指向非静态成员的指针</a>。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> S
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> m<span class="sy4">;</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> S<span class="sy4">::</span><span class="sy2">*</span>p <span class="sy1">=</span> <span class="sy3">&</span>S<span class="sy4">::</span><span class="me2">m</span><span class="sy4">;</span> <span class="co1">// OK:m 用于构成成员指针</span>
|
|
<span class="kw4">void</span> <span class="br0">(</span>S<span class="sy4">::</span><span class="sy2">*</span>fp<span class="br0">)</span><span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> <span class="sy3">&</span>S<span class="sy4">::</span><span class="me2">f</span><span class="sy4">;</span> <span class="co1">// OK:f 用于构成成员指针</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> (仅对数据成员,而非成员函数)当在<a href="cpp-language-expressions.html#.E4.B8.8D.E6.B1.82.E5.80.BC.E8.A1.A8.E8.BE.BE.E5.BC.8F">不求值操作数</a>中使用时。
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> S
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> m<span class="sy4">;</span>
|
|
<span class="kw4">static</span> <span class="kw4">const</span> <a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> sz <span class="sy1">=</span> sizeof m<span class="sy4">;</span> <span class="co1">// OK:不求值操作数中的 m</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> j <span class="sy1">=</span> sizeof<span class="br0">(</span>S<span class="sy4">::</span><span class="me2">m</span> <span class="sy2">+</span> <span class="nu0">42</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK:即便没有 m 的 "this" 对象</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="t-li1"><span class="t-li"></span> 注:这种用法是经由 <a rel="nofollow" class="external text" href="https://wg21.link/N2253">N2253</a> 中 CWG 问题 613 的解决方案允许的,某些编译器(例如 clang)认为它是 C++11 中的改动。</div>
|
|
<h3><span class="mw-headline" id=".E7.BC.BA.E9.99.B7.E6.8A.A5.E5.91.8A">缺陷报告</span></h3>
|
|
<p>下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。</p>
|
|
<table class="dsctable" style="font-size:0.8em">
|
|
<tr>
|
|
<th>DR</th>
|
|
<th>应用于</th>
|
|
<th>出版时的行为</th>
|
|
<th>正确行为</th>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue80">CWG 80</a></td>
|
|
<td>C++98</td>
|
|
<td>所有数据成员的名字不能与类名相同(与 C 不兼容)</td>
|
|
<td>非静态数据成员的名字在没有用户<br />
|
|
声明的构造函数时可以与类名相同</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue613">CWG 613</a></td>
|
|
<td>C++98</td>
|
|
<td>不允许非静态数据成员的不求值使用</td>
|
|
<td>允许这种使用</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1397">CWG 1397</a></td>
|
|
<td>C++11</td>
|
|
<td>在默认成员初始化器中类被视为完整的</td>
|
|
<td>默认成员初始化不能触发默认构造函数的定义</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1696">CWG 1696</a></td>
|
|
<td>C++98</td>
|
|
<td>引用成员能初始化为临时量(其生存期会在构造函数结束时结束)</td>
|
|
<td>这种初始化非良构</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue1719">CWG 1719</a></td>
|
|
<td>C++98</td>
|
|
<td>cv 限定不同的类型曾经不是布局兼容的</td>
|
|
<td>忽略 cv 限定,改进规范</td>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue2254">CWG 2254</a></td>
|
|
<td>C++11</td>
|
|
<td>指向无数据成员的标准布局类的指针能 reinterpret_cast 到其首个基类</td>
|
|
<td>能 reinterpret_cast 到其任意基类</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<table class="t-dsc-begin">
|
|
<tr class="t-dsc">
|
|
<td colspan="2"><a href="cpp-language-classes.html">类</a></td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td colspan="2"><a href="cpp-language-static.html">静态成员</a></td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td colspan="2"><a href="cpp-language-member_functions.html">非静态成员函数</a></td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td>
|
|
<div class="t-dsc-member-div">
|
|
<div><a href="cpp-types-is_standard_layout.html"><span class="t-lines"><span>is_standard_layout</span></span></a></div>
|
|
<div><span class="t-lines"><span><span class="t-mark-rev t-since-cxx11">(C++11)</span></span></span></div>
|
|
</div>
|
|
</td>
|
|
<td>检查是否是一个标准布局类型<br />
|
|
<span class="t-mark">(类模板)</span></td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td>
|
|
<div class="t-dsc-member-div">
|
|
<div><a href="cpp-types-offsetof.html"><span class="t-lines"><span>offsetof</span></span></a></div>
|
|
</div>
|
|
</td>
|
|
<td>从标准布局类型的起始到其指定成员的字节偏移量<br />
|
|
<span class="t-mark">(宏函数)</span></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|