206 lines
23 KiB
HTML
206 lines
23 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_static 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-keywords-static.html" class="mw-redirect"><tt>static</tt></a> 声明不绑定到类实例的成员。</p>
|
|
<p>在类定义之外,它有不同含义:见<a href="cpp-language-storage_duration.html">存储期</a>。</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><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">static</span></span></span> <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-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">static</span></span></span> <span class="t-spar">成员函数</span></td>
|
|
<td>(2)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1)</span> 声明静态数据成员。</div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 声明静态成员函数。</div>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>类的静态成员不与类的对象关联:它们是具有<a href="cpp-language-storage_duration.html">静态<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>的独立变量,或者常规函数。</p>
|
|
<p><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">static</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">class</span> X <span class="br0">{</span> <span class="kw4">static</span> <span class="kw4">int</span> n<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 声明(用 'static')</span>
|
|
<span class="kw4">int</span> X<span class="sy4">::</span><span class="me2">n</span> <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// 定义(不用 'static')</span></pre></div>
|
|
</div>
|
|
<p>类体内的声明不是定义,且可以将成员声明为(除 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span></span></span> 之外的)<a href="cpp-language-type.html#.E4.B8.8D.E5.AE.8C.E6.95.B4.E7.B1.BB.E5.9E.8B">不完整类型</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> Foo<span class="sy4">;</span>
|
|
<span class="kw1">struct</span> S
|
|
<span class="br0">{</span>
|
|
<span class="kw4">static</span> <span class="kw4">int</span> a<span class="br0">[</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 声明,不完整类型</span>
|
|
<span class="kw4">static</span> Foo x<span class="sy4">;</span> <span class="co1">// 声明,不完整类型</span>
|
|
<span class="kw4">static</span> S s<span class="sy4">;</span> <span class="co1">// 声明,不完整类型(在其自身定义中)</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> S<span class="sy4">::</span><span class="me2">a</span><span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 定义,完整类型</span>
|
|
<span class="kw1">struct</span> Foo <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
Foo S<span class="sy4">::</span><span class="me2">x</span><span class="sy4">;</span> <span class="co1">// 定义,完整类型</span>
|
|
S S<span class="sy4">::</span><span class="me2">s</span><span class="sy4">;</span> <span class="co1">// 定义,完整类型</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<p>然而如果声明使用了 <a href="cpp-language-constexpr.html"><tt>constexpr</tt></a> <span class="t-rev-inl t-since-cxx17"><span>或 <a href="cpp-language-inline.html"><tt>inline</tt></a></span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span> 说明符,那么该成员必须声明为拥有完整类型。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>指代类 <code>T</code> 的静态成员 <code>m</code> 有两种可用的形式:限定名 <code>T::m</code>以及成员访问表达式 <code>E.m</code> 或 <code>E->m</code>,其中 <code>E</code> 分别是求值为 <code>T</code> 或 <code>T*</code> 的表达式。在同一类作用域中时,不需要限定:</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">static</span> <span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 声明</span>
|
|
<span class="kw4">static</span> <span class="kw4">int</span> n<span class="sy4">;</span> <span class="co1">// 声明</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
X g<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> X<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// 某个返回 X 的函数</span>
|
|
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
X<span class="sy4">::</span><span class="me2">f</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// X::f 是静态成员函数的限定名</span>
|
|
g<span class="br0">(</span><span class="br0">)</span>.<span class="me1">f</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// g().f 是指代静态成员函数的成员访问表达式</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">int</span> X<span class="sy4">::</span><span class="me2">n</span> <span class="sy1">=</span> <span class="nu0">7</span><span class="sy4">;</span> <span class="co1">// 定义</span>
|
|
|
|
<span class="kw4">void</span> X<span class="sy4">::</span><span class="me2">f</span><span class="br0">(</span><span class="br0">)</span> <span class="co1">// 定义</span>
|
|
<span class="br0">{</span>
|
|
n <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// X::n 在此作用域可以只要以 n 的形式进行访问</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>静态成员遵循<a href="cpp-language-access.html">类成员访问规则(私有、受保护、公开)</a>。</p>
|
|
<h4><span class="mw-headline" id=".E9.9D.99.E6.80.81.E6.88.90.E5.91.98.E5.87.BD.E6.95.B0">静态成员函数</span></h4>
|
|
<p>静态成员函数不关联到任何对象。调用时,它们没有 <span class="t-c"><span class="mw-geshi cpp source-cpp">this</span></span> 指针。</p>
|
|
<p>静态成员函数不能是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">virtual</span></span></span>、<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">const</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">volatile</span></span></span> 的。</p>
|
|
<p>静态成员函数的地址可以存储在常规的<a href="cpp-language-pointer.html#.E5.87.BD.E6.95.B0.E6.8C.87.E9.92.88">函数指针</a>中,但不能存储在<a href="cpp-language-pointer.html#.E6.88.90.E5.91.98.E5.87.BD.E6.95.B0.E6.8C.87.E9.92.88">成员函数指针</a>中。</p>
|
|
<h4><span class="mw-headline" id=".E9.9D.99.E6.80.81.E6.95.B0.E6.8D.AE.E6.88.90.E5.91.98">静态数据成员</span></h4>
|
|
<p>静态数据成员不关联到任何对象。即使不定义类的任何对象它们也存在。整个程序中只有一个拥有静态<a href="cpp-language-storage_duration.html">存储期</a>的静态数据成员实例<span class="t-rev-inl t-since-cxx11"><span>,除非使用关键词 <a href="cpp-keyword-thread_local.html"><tt>thread_local</tt></a>,此时每个线程都有一个具有线程存储期的该对象</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></span></span>。</p>
|
|
<p>静态数据成员不能是 <span class="t-c"><span class="mw-geshi cpp source-cpp">mutable</span></span> 的。</p>
|
|
<p>在命名空间作用域中,如果类自身具有外部连接(即不是<a href="cpp-language-namespace.html#.E6.97.A0.E5.90.8D.E5.91.BD.E5.90.8D.E7.A9.BA.E9.97.B4">无名命名空间</a>的成员),那么类的静态数据成员也具有<a href="cpp-language-storage_duration.html">外部连接</a>。局部类(定义于函数内部的类)和无名类,包括无名类的成员类,不能拥有静态数据成员。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<p>静态数据成员可以声明为 <a href="cpp-language-inline.html"><tt>inline</tt></a>。 inline 静态数据成员可以在类定义中定义,而且可以指定初始化器。它不需要类外定义:</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="kw1">inline</span> <span class="kw4">static</span> <span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E5.B8.B8.E9.87.8F.E9.9D.99.E6.80.81.E6.88.90.E5.91.98">常量静态成员</span></h4>
|
|
<p>如果整型或枚举类型的静态数据成员被声明为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">const</span></span></span>(且非 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">volatile</span></span></span>),那么它能以其中的每个表达式均为<a href="cpp-language-constexpr.html">常量表达式</a>的<a href="cpp-language-initialization.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> X
|
|
<span class="br0">{</span>
|
|
<span class="kw4">const</span> <span class="kw4">static</span> <span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span>
|
|
<span class="kw4">const</span> <span class="kw4">static</span> <span class="kw4">int</span> m<span class="br0">{</span><span class="nu0">2</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// C++11 起</span>
|
|
<span class="kw4">const</span> <span class="kw4">static</span> <span class="kw4">int</span> k<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span> X<span class="sy4">::</span><span class="me2">k</span> <span class="sy1">=</span> <span class="nu0">3</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<p>如果声明<a href="cpp-named_req-LiteralType.html"><span style="font-style:italic">字面类型</span> <span style="font-family: Georgia, 'DejaVu Serif', serif; font-style:italic">(LiteralType)</span></a> 的静态数据成员为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</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> X <span class="br0">{</span>
|
|
<span class="kw4">constexpr</span> <span class="kw4">static</span> <span class="kw4">int</span> arr<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">// OK</span>
|
|
<span class="kw4">constexpr</span> <span class="kw4">static</span> <a href="cpp-numeric-complex.html"><span class="kw1472">std::<span class="me2">complex</span></span></a><span class="sy1"><</span><span class="kw4">double</span><span class="sy1">></span> n <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">// OK</span>
|
|
<span class="kw4">constexpr</span> <span class="kw4">static</span> <span class="kw4">int</span> k<span class="sy4">;</span> <span class="co1">// 错误:constexpr static 要求初始化器</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>如果 const <span class="t-rev-inl t-since-cxx17"><span>非 inline</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span>静态数据成员<span class="t-rev-inl t-since-cxx11 t-until-cxx17"><span>或 constexpr 静态数据成员</span> <span><span class="t-mark-rev t-since-cxx11">(C++11 起)</span><br />
|
|
<span class="t-mark-rev t-until-cxx17">(C++17 前)</span></span></span>被 <a href="cpp-language-definition.html#ODR_.E5.BC.8F.E4.BD.BF.E7.94.A8">ODR 式使用</a>,那么仍然需要命名空间作用域的定义,但它不能有初始化器。<span class="t-rev-inl t-since-cxx17"><span>可以提供定义,尽管这是冗余的</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</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> X <span class="br0">{</span>
|
|
<span class="kw4">static</span> <span class="kw4">const</span> <span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span>
|
|
<span class="kw4">static</span> <span class="kw4">constexpr</span> <span class="kw4">int</span> m <span class="sy1">=</span> <span class="nu0">4</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span> <span class="sy2">*</span>p <span class="sy1">=</span> <span class="sy3">&</span>X<span class="sy4">::</span><span class="me2">n</span>, <span class="sy2">*</span>q <span class="sy1">=</span> <span class="sy3">&</span>X<span class="sy4">::</span><span class="me2">m</span><span class="sy4">;</span> <span class="co1">// 因为X::n 与 X::m 被 ODR 式使用</span>
|
|
<span class="kw4">const</span> <span class="kw4">int</span> X<span class="sy4">::</span><span class="me2">n</span><span class="sy4">;</span> <span class="co1">// ……所以需要定义</span>
|
|
<span class="kw4">constexpr</span> <span class="kw4">int</span> X<span class="sy4">::</span><span class="me2">m</span><span class="sy4">;</span> <span class="co1">// ……(但 C++17 中的 X::m 不需要)</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx17">
|
|
<td>
|
|
<p>如果静态数据成员被声明为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">constexpr</span></span></span>,那么它隐含为 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">inline</span></span></span> 且不必在命名空间作用域重声明。这种无初始化器的重声明(之前则需要,如上所示)仍然得到容许,但已被弃用。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.BC.95.E7.94.A8">引用</span></h3>
|
|
<div class="t-ref-std-c++11">
|
|
<ul>
|
|
<li>C++11 标准(ISO/IEC 14882:2011):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>9.4 Static members [class.static]</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>9.4 Static members [class.static]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<ul>
|
|
<li><a href="cpp-language-storage_duration.html"><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">static</span></span></span> 存储说明符</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|