458 lines
56 KiB
HTML
458 lines
56 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_scope 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>C++ 程序中出现的每个<a href="cpp-language-name.html" class="mw-redirect">名字</a>,只在某些可能不连续的源码部分中有效,这些部分被称为其<i>作用域</i>。</p>
|
|
<p>在作用域内,能用<a href="cpp-language-lookup.html">无限定名字查找</a>将名字与其声明关联起来。</p>
|
|
<h3><span class="mw-headline" id=".E5.9D.97.E4.BD.9C.E7.94.A8.E5.9F.9F">块作用域</span></h3>
|
|
<p><a href="cpp-language-statements.html#.E5.A4.8D.E5.90.88.E8.AF.AD.E5.8F.A5">块(复合语句)</a>中的声明所引入的变量的潜在作用域,开始于其声明点并终止于该块末尾。实际作用域与潜在作用域相同,除非有内嵌块带有引入了相同名字的声明(这种情况下,从外层声明的作用域中排除掉嵌套声明的整个潜在作用域)。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> a <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> <span class="co1">// 第一个 'a' 的作用域开始</span>
|
|
<span class="sy2">++</span>a<span class="sy4">;</span> <span class="co1">// 名字 'a' 在作用域中并指代第一个 'a'</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> a <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// 第二个 'a' 的作用域开始</span>
|
|
<span class="co1">// 第一个 'a' 的作用域间断</span>
|
|
a <span class="sy1">=</span> <span class="nu0">42</span><span class="sy4">;</span> <span class="co1">// 'a' 在作用域中并指代第二个 'a'</span>
|
|
<span class="br0">}</span> <span class="co1">// 块结束,第二个 'a' 的作用域结束</span>
|
|
<span class="co1">// 第一个 'a' 的作用域恢复</span>
|
|
<span class="br0">}</span> <span class="co1">// 块结束,第一个 'a' 的作用域结束</span>
|
|
<span class="kw4">int</span> b <span class="sy1">=</span> a<span class="sy4">;</span> <span class="co1">// 错误:名字 'a' 不在作用域中</span></pre></div>
|
|
</div>
|
|
<p>声明于异常处理块中的名字的潜在作用域开始于其声明点,并在该异常处理块结束时结束,其他异常处理块和外围块在作用域以外。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">try</span> <span class="br0">{</span>
|
|
f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span> <span class="kw1">catch</span><span class="br0">(</span><span class="kw4">const</span> <a href="cpp-error-runtime_error.html"><span class="kw770">std::<span class="me2">runtime_error</span></span></a><span class="sy3">&</span> re<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// re 的作用域开始</span>
|
|
<span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// n 的作用开始</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> re.<span class="me1">what</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// re 在作用域中</span>
|
|
<span class="br0">}</span> <span class="co1">// re 的作用域结束, n 的作用域结束</span>
|
|
<span class="kw1">catch</span><span class="br0">(</span><a href="cpp-error-exception.html"><span class="kw764">std::<span class="me2">exception</span></span></a><span class="sy3">&</span> e<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> re.<span class="me1">what</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误: re 不在作用域中</span>
|
|
<span class="sy2">++</span>n<span class="sy4">;</span> <span class="co1">// 错误: n 不在作用域中</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>声明于 <a href="cpp-language-for.html">for 循环</a>的<i>初始化语句</i>,<a href="cpp-language-for.html">for 循环</a>的<i>条件</i>,<a href="cpp-language-range-for.html">范围 for 循环</a>的<i>范围声明</i>,<span class="t-rev-inl t-since-cxx17"><span><a href="cpp-language-if.html">if 语句</a>或 <a href="cpp-language-switch.html">switch 语句</a>的<i>初始化语句</i>,</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span><a href="cpp-language-if.html">if 语句</a>、<a href="cpp-language-while.html">while 循环</a>或 <a href="cpp-language-switch.html">switch 语句</a>的<i>条件</i>中的名字的潜在作用域开始于其声明点,并结束于相应控制语句的末尾。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1">Base<span class="sy2">*</span> bp <span class="sy1">=</span> new Derived<span class="sy4">;</span>
|
|
<span class="kw1">if</span><span class="br0">(</span>Derived<span class="sy2">*</span> dp <span class="sy1">=</span> <span class="kw1">dynamic_cast</span><span class="sy1"><</span>Derived<span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span>bp<span class="br0">)</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
dp<span class="sy2">-</span><span class="sy1">></span>f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// dp 在作用域中</span>
|
|
<span class="br0">}</span> <span class="co1">// dp 的作用域结束</span>
|
|
|
|
<span class="kw1">for</span><span class="br0">(</span><span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> <span class="co1">// n 的作用域开始</span>
|
|
n <span class="sy1"><</span> <span class="nu0">10</span><span class="sy4">;</span> <span class="co1">// n 在作用域中</span>
|
|
<span class="sy2">++</span>n<span class="br0">)</span> <span class="co1">// n 在作用域中</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> n <span class="sy1"><<</span> <span class="st0">' '</span><span class="sy4">;</span> <span class="co1">// n 在作用域中</span>
|
|
<span class="br0">}</span> <span class="co1">// n 的作用域结束</span></pre></div>
|
|
</div>
|
|
<p><span id=".E5.87.BD.E6.95.B0.E5.8E.9F.E5.9E.8B.E4.BD.9C.E7.94.A8.E5.9F.9F"></span></p>
|
|
<h3><span class="mw-headline" id=".E5.87.BD.E6.95.B0.E5.BD.A2.E5.8F.82.E4.BD.9C.E7.94.A8.E5.9F.9F">函数形参作用域</span></h3>
|
|
<p>函数形参(包括 <code>lambda</code> 表达式的形参)或函数局部预定义变量的潜在作用域开始于其声明点。</p>
|
|
<ul>
|
|
<li>若最内层的外围函数声明符不是函数定义的声明符,则其潜在作用域终止于该函数声明符的结尾。</li>
|
|
<li>否则,其潜在作用域终止于<a href="cpp-language-function-try-block.html">函数 try 块</a>的最后异常处理块的末尾,若不使用函数 try 块则为函数体的末尾。</li>
|
|
</ul>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">const</span> <span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">3</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span> f1<span class="br0">(</span><span class="kw4">int</span> n, <span class="co1">// 全局 'n' 的作用域间断</span>
|
|
<span class="co1">// 形参 'n' 的作用域开始</span>
|
|
<span class="kw4">int</span> y <span class="sy1">=</span> n<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误:默认实参涉指了形参</span>
|
|
|
|
<span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span><span class="br0">(</span><span class="sy2">*</span>f2<span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span> n<span class="br0">)</span><span class="br0">)</span><span class="br0">[</span>n<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// OK :函数形参 'n' 的作用域终止于其函数声明符的末尾</span>
|
|
<span class="co1">// 在数组声明符中,全局 n 在作用域中</span>
|
|
<span class="co1">// (这声明了一个返回(含有 3 个 int 元素的数组的指针)的函数的指针)</span>
|
|
|
|
<span class="co1">// 相反</span>
|
|
<span class="kw4">auto</span> <span class="br0">(</span><span class="sy2">*</span>f3<span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span> n<span class="br0">)</span><span class="sy2">-</span><span class="sy1">></span><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">[</span>n<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误:以形参 'n' 为数组边界</span>
|
|
|
|
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">2</span><span class="br0">)</span> <span class="co1">// 'n' 的作用域开始</span>
|
|
<span class="kw1">try</span> <span class="co1">// 函数 try 块</span>
|
|
<span class="br0">{</span> <span class="co1">// 函数体开始</span>
|
|
<span class="sy2">++</span>n<span class="sy4">;</span> <span class="co1">// 'n' 在作用域中并指代函数形参</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> <span class="co1">// 局部变量 'n' 的作用域开始</span>
|
|
<span class="co1">// 函数形参 'n' 的作用域中断</span>
|
|
<span class="sy2">++</span>n<span class="sy4">;</span> <span class="co1">// 'n' 在此块中指代局部变量</span>
|
|
<span class="br0">}</span> <span class="co1">// 局部变量 'n' 的作用域结束</span>
|
|
<span class="co1">// 函数形参 'n' 的作用域恢复</span>
|
|
<span class="br0">}</span> <span class="kw1">catch</span><span class="br0">(</span>...<span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="sy2">++</span>n<span class="sy4">;</span> <span class="co1">// n 在作用域中并指代函数形参</span>
|
|
<span class="kw1">throw</span><span class="sy4">;</span>
|
|
<span class="br0">}</span> <span class="co1">// 最后异常处理块结束,函数形参 'n' 的作用域结束</span>
|
|
<span class="kw4">int</span> a <span class="sy1">=</span> n<span class="sy4">;</span> <span class="co1">// OK :全局 'n' 在作用域中</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.87.BD.E6.95.B0.E4.BD.9C.E7.94.A8.E5.9F.9F">函数作用域</span></h3>
|
|
<p>如果一个<a href="cpp-language-statements.html#.E6.A0.87.E5.8F.B7">标号(且只有标号)</a>在一个函数内声明,则在该函数和其所有内嵌代码块的任何位置,无论在其自身声明的前后,该标号都在作用域中。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">goto</span> label<span class="sy4">;</span> <span class="co1">// label 在作用域中,尽管之后才声明</span>
|
|
label<span class="sy4">:;</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw1">goto</span> label<span class="sy4">;</span> <span class="co1">// label 忽略块作用域</span>
|
|
<span class="br0">}</span>
|
|
|
|
<span class="kw4">void</span> g<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">goto</span> label<span class="sy4">;</span> <span class="co1">// 错误: g() 中 label 不在作用域中</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.91.BD.E5.90.8D.E7.A9.BA.E9.97.B4.E4.BD.9C.E7.94.A8.E5.9F.9F">命名空间作用域</span></h3>
|
|
<p><a href="cpp-language-namespace.html">命名空间</a>中声明的任何实体的潜在作用域均开始于其声明,并由其后的同一命名空间名的所有命名空间定义拼合起来,再加上对于将这个名字或其整个命名空间引入到其他作用域的每个 <a href="cpp-language-namespace.html">using 指令</a>来说,包括这个作用域的剩余部分。</p>
|
|
<p>翻译单元的顶层作用域(“文件作用域”或“全局作用域”)亦为命名空间,且被正式称作“全局命名空间作用域”。任何声明于全局命名空间作用域的实体的潜在作用域均开始于其声明,并持续到翻译单元的结尾。</p>
|
|
<p>声明于无名命名空间或内联命名空间的实体的作用域包括外围命名空间;</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">namespace</span> N <span class="br0">{</span> <span class="co1">// N 的作用域开始(作为全局命名空间的成员)</span>
|
|
<span class="kw4">int</span> i<span class="sy4">;</span> <span class="co1">// i 的作用域开始</span>
|
|
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">int</span> a<span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> a<span class="sy4">;</span> <span class="br0">}</span> <span class="co1">// g 的作用域开始</span>
|
|
<span class="kw4">int</span> j<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// j 的作用域开始</span>
|
|
<span class="kw4">void</span> q<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// q 的作用域开始</span>
|
|
<span class="kw1">namespace</span> <span class="br0">{</span>
|
|
<span class="kw4">int</span> x<span class="sy4">;</span> <span class="co1">// x 的作用域开始</span>
|
|
<span class="br0">}</span> <span class="co1">// x 的作用域不结束</span>
|
|
<span class="kw1">inline</span> <span class="kw1">namespace</span> inl <span class="br0">{</span> <span class="co1">// inl 的作用域开始</span>
|
|
<span class="kw4">int</span> y<span class="sy4">;</span> <span class="co1">// y 的作用域开始</span>
|
|
<span class="br0">}</span> <span class="co1">// y 的作用域不结束</span>
|
|
<span class="br0">}</span> <span class="co1">// i、g、j、q、inl、x、y 的作用域间断</span>
|
|
|
|
<span class="kw1">namespace</span> <span class="br0">{</span>
|
|
<span class="kw4">int</span> l<span class="sy1">=</span><span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// l 的作用域开始</span>
|
|
<span class="br0">}</span> <span class="co1">// l 的作用域不结束(它是无名命名空间的成员)</span>
|
|
|
|
<span class="kw1">namespace</span> N <span class="br0">{</span> <span class="co1">// i、g、j、q、inl、x、y 的作用域继续</span>
|
|
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">char</span> a<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// 重载 N::g(int)</span>
|
|
<span class="kw1">return</span> l<span class="sy2">+</span>a<span class="sy4">;</span> <span class="co1">// 来自无名命名空间的 l 在作用域中</span>
|
|
<span class="br0">}</span>
|
|
<span class="co1">// int i; // 错误:重复定义( i 已在作用域中)</span>
|
|
<span class="kw4">int</span> j<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK :允许重复的函数声明</span>
|
|
<span class="kw4">int</span> j<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="co1">// OK :定义先前声明的 N::j()</span>
|
|
<span class="kw1">return</span> g<span class="br0">(</span>i<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 调用 N::g(int)</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw4">int</span> q<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 错误: q 已在作用域中并有不同的返回类型</span>
|
|
<span class="br0">}</span> <span class="co1">// i、g、j、q、inl、x、y 的作用域间断</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">using</span> <span class="kw1">namespace</span> N<span class="sy4">;</span> <span class="co1">// i、g、j、q、inl、x、y 的作用域恢复</span>
|
|
i <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// N::i 在作用域中</span>
|
|
x <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// N::(匿名)::x 在作用域中</span>
|
|
y <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// N::inl::y 在作用域中</span>
|
|
inl<span class="sy4">::</span><span class="me2">y</span> <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> <span class="co1">// N::inl 也在作用域中</span>
|
|
<span class="br0">}</span> <span class="co1">// i、g、j、q、inl、x、y 的作用域间断</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E7.B1.BB.E4.BD.9C.E7.94.A8.E5.9F.9F">类作用域</span></h3>
|
|
<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> X <span class="br0">{</span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">int</span> a <span class="sy1">=</span> n<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// 默认实参内的 X::n 在作用域中</span>
|
|
<span class="kw1">return</span> a<span class="sy2">*</span>n<span class="sy4">;</span> <span class="co1">// 函数体内的 X::n 在作用域中</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw1">using</span> r <span class="sy1">=</span> <span class="kw4">int</span><span class="sy4">;</span>
|
|
r g<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> i <span class="sy1">=</span> n<span class="sy2">*</span><span class="nu0">2</span><span class="sy4">;</span> <span class="co1">// 初始化器内的 X::n 在作用域中</span>
|
|
|
|
<span class="co1">// int x[n]; // 错误:类体内的 X::n 不在作用域中</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">int</span> x<span class="br0">[</span>n<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// OK : 类体内的 X::n 现在在作用域中</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">//r X::g() { // 错误:类外成员函数内的 r 不在作用域中</span>
|
|
<span class="kw4">auto</span> X<span class="sy4">::</span><span class="me2">g</span><span class="br0">(</span><span class="br0">)</span><span class="sy2">-</span><span class="sy1">></span>r <span class="br0">{</span> <span class="co1">// OK :尾随返回类型内的 X::r 在作用域中</span>
|
|
<span class="kw1">return</span> n<span class="sy4">;</span> <span class="co1">// 类外成员函数体内的 X::n 在作用域中</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>如果一个名字在被声明前已经在类体中被使用,而该名字的另一声明在作用域中,则程序<a href="cpp-language-ub.html">非良构,不要求诊断</a>。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">typedef</span> <span class="kw4">int</span> c<span class="sy4">;</span> <span class="co1">// ::c</span>
|
|
<span class="kw2">enum</span> <span class="br0">{</span> i <span class="sy1">=</span> <span class="nu0">1</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// ::i</span>
|
|
<span class="kw1">class</span> X <span class="br0">{</span>
|
|
<span class="kw4">char</span> v<span class="br0">[</span>i<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误:此处 i 指代 ::i,但 X::i 也存在</span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">return</span> sizeof<span class="br0">(</span>c<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK :成员函数体内在作用域中的是 X::c 而非 ::c</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw4">char</span> c<span class="sy4">;</span> <span class="co1">// X::c</span>
|
|
<span class="kw2">enum</span> <span class="br0">{</span> i <span class="sy1">=</span> <span class="nu0">2</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// X::i</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">typedef</span> <span class="kw4">char</span><span class="sy2">*</span> T<span class="sy4">;</span>
|
|
<span class="kw1">struct</span> Y <span class="br0">{</span>
|
|
T a<span class="sy4">;</span> <span class="co1">// 错误:此处,T 指代 ::T,但 Y::T 也存在</span>
|
|
<span class="kw1">typedef</span> <span class="kw4">long</span> T<span class="sy4">;</span>
|
|
T b<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>任何类成员名只能用于四种语境中:</p>
|
|
<ul>
|
|
<li>在其自身的类作用域或在派生类的类作用域之中</li>
|
|
<li>在对其类或其派生类的类型的表达式运用 <code><b>.</b></code> 运算符之后</li>
|
|
<li>在对其类或其派生的类的指针类型的表达式运用 <code><b>-></b></code> 运算符之后</li>
|
|
<li>在对其类或其派生类的名字运用 <code><b>::</b></code> 运算符之后</li>
|
|
</ul>
|
|
<h3><span class="mw-headline" id=".E6.9E.9A.E4.B8.BE.E4.BD.9C.E7.94.A8.E5.9F.9F">枚举作用域</span></h3>
|
|
<p><a href="cpp-language-enum.html">有作用域枚举</a>中引入的枚举项的名字的作用域开始于其声明点,并终止于 enum 说明符的末尾(与之相反,无作用域枚举项在 enum 说明符的结束后仍在作用域中):</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw2">enum</span> e1_t <span class="br0">{</span> <span class="co1">// 无作用域枚举</span>
|
|
A,
|
|
B <span class="sy1">=</span> A<span class="sy2">*</span><span class="nu0">2</span>
|
|
<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// A 与 B 的作用域不结束</span>
|
|
|
|
<span class="kw2">enum</span> <span class="kw1">class</span> e2_t <span class="br0">{</span> <span class="co1">// 有作用域枚举</span>
|
|
SA,
|
|
SB <span class="sy1">=</span> SA<span class="sy2">*</span><span class="nu0">2</span> <span class="co1">// SA 在作用域中</span>
|
|
<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// SA 与 SB 的作用域结束</span>
|
|
|
|
e1_t e1 <span class="sy1">=</span> B<span class="sy4">;</span> <span class="co1">// OK : B 在作用域中</span>
|
|
<span class="co1">// e2_t e2 = SB; // 错误: SB 不在作用域中</span>
|
|
e2_t e2 <span class="sy1">=</span> e2_t<span class="sy4">::</span><span class="me2">SB</span><span class="sy4">;</span> <span class="co1">// OK</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E6.A8.A1.E6.9D.BF.E5.BD.A2.E5.8F.82.E4.BD.9C.E7.94.A8.E5.9F.9F">模板形参作用域</span></h3>
|
|
<p>模板形参名的潜在作用域直接开始于其声明点,并持续到于其中引入了它的最小模板声明的末尾。具体而言,模板形参能用于其后的模板形参的声明及基类的指定,但不能用于其前的模板形参的声明。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span> <span class="kw1">typename</span> T, <span class="co1">// T 的作用域开始</span>
|
|
T<span class="sy2">*</span> p, <span class="co1">// T 能用于非类型形参</span>
|
|
<span class="kw1">class</span> U <span class="sy1">=</span> T <span class="co1">// T 能用作默认类型</span>
|
|
<span class="sy1">></span>
|
|
<span class="kw1">class</span> X <span class="sy4">:</span> <span class="kw1">public</span> Array<span class="sy1"><</span>T<span class="sy1">></span> <span class="co1">// T 能用于基类名</span>
|
|
<span class="br0">{</span>
|
|
<span class="co1">// T 还能在体内使用</span>
|
|
<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// T 与 U 的作用域结束, X 的作用域持续</span></pre></div>
|
|
</div>
|
|
<p>模板模板形参的形参名的潜在作用域,是该名字出现于其中的最小模板形参列表</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span> <span class="kw1">template</span><span class="sy1"><</span> <span class="co1">// 模板模板形参</span>
|
|
<span class="kw1">typename</span> Y, <span class="co1">// Y 的作用域开始</span>
|
|
<span class="kw1">typename</span> G <span class="sy1">=</span> Y <span class="co1">// Y 在作用域中</span>
|
|
<span class="sy1">></span> <span class="co1">// Y 与 G 的作用域结束</span>
|
|
<span class="kw1">class</span> T,
|
|
<span class="co1">// typename U = Y // 错误: Y 不在作用域中</span>
|
|
<span class="kw1">typename</span> U
|
|
<span class="sy1">></span>
|
|
<span class="kw1">class</span> X
|
|
<span class="br0">{</span>
|
|
<span class="br0">}</span><span class="sy4">;</span> <span class="co1">// T 与 U 的作用域结束</span></pre></div>
|
|
</div>
|
|
<p>与其他嵌套作用域类似,模板形参名在其自身的持续期间隐藏来自外层作用域的相同名字:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">typedef</span> <span class="kw4">int</span> N<span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span> N X, <span class="co1">// int 类型的非类型模板形参</span>
|
|
<span class="kw1">typename</span> N, <span class="co1">// 此 N 的作用域开始,::N 的作用域中断</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span>N Y<span class="sy1">></span> <span class="kw1">class</span> T <span class="co1">// 此处的 N 是模板形参,非 int</span>
|
|
<span class="sy1">></span> <span class="kw1">struct</span> A<span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.A3.B0.E6.98.8E.E7.82.B9">声明点</span></h3>
|
|
<p>作用域始于<i>声明点</i>,它定位如下:</p>
|
|
<p>对于简单声明所引入的变量和其他名字,声明点紧随该名字的<a href="cpp-language-declarations.html#.E5.A3.B0.E6.98.8E.E7.AC.A6">声明符</a>之后,且在其初始化器之前(若其存在):</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">unsigned</span> <span class="kw4">char</span> x <span class="sy1">=</span> <span class="nu0">32</span><span class="sy4">;</span> <span class="co1">// 第一个 'x' 的作用域开始</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">unsigned</span> <span class="kw4">char</span> x <span class="sy1">=</span> x<span class="sy4">;</span> <span class="co1">// 第二个 'x' 的作用域在初始化器(= x)前开始</span>
|
|
<span class="co1">// 这导致第二个 'x' 不以值 32 初始化,</span>
|
|
<span class="co1">// 而是以其自身的不确定值初始化</span>
|
|
<span class="br0">}</span>
|
|
<a href="cpp-utility-functional-function.html"><span class="kw1059">std::<span class="me2">function</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy1">></span> f <span class="sy1">=</span> <span class="br0">[</span><span class="sy3">&</span><span class="br0">]</span><span class="br0">(</span><span class="kw4">int</span> n<span class="br0">)</span><span class="br0">{</span><span class="kw1">return</span> n<span class="sy1">></span><span class="nu0">1</span> <span class="sy4">?</span> n<span class="sy2">*</span>f<span class="br0">(</span>n<span class="sy2">-</span><span class="nu0">1</span><span class="br0">)</span> <span class="sy4">:</span> n<span class="sy4">;</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// lambda 内的函数对象名 'f' 在作用域中,</span>
|
|
<span class="co1">// 而且能正确地被按引用俘获,给出递归函数</span></pre></div>
|
|
</div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">const</span> <span class="kw4">int</span> x <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> <span class="co1">// 第一个 'x' 的作用域开始</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> x<span class="br0">[</span>x<span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 第二个 x 的作用域在初始化器(= {})前,但在声明器(x[x])后开始。</span>
|
|
<span class="co1">// 在声明器内,外层 'x' 仍在作用域中,这声明了一个含有 2 个 int 元素的数组。</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>类或类模板的声明点紧随其<a href="cpp-language-classes.html">类头</a>中所出现的命名该类的标识符(或命名该模板特化的 <a href="cpp-language-templates.html#template-id">模板标识</a>)之后,并且在基类列表内已处于作用域中:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co1">// 名称 'S' 在其出现后立即处于作用域中,</span>
|
|
<span class="co1">// 故它能用于基类列表</span>
|
|
<span class="kw1">struct</span> S<span class="sy4">:</span> <a href="cpp-memory-enable_shared_from_this.html"><span class="kw744">std::<span class="me2">enable_shared_from_this</span></span></a><span class="sy1"><</span>S<span class="sy1">></span>
|
|
<span class="br0">{</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>枚举的声明点紧随 <a href="cpp-language-enum.html">enum 说明符</a>或笼统枚举声明(取决于先使用者)中所出现的命名它的标识符之后:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw2">enum</span> E <span class="sy4">:</span> <span class="kw4">int</span> <span class="br0">{</span> <span class="co1">// E 已在作用域中</span>
|
|
A <span class="sy1">=</span> sizeof<span class="br0">(</span>E<span class="br0">)</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p><a href="cpp-language-type_alias.html">类型别名或别名模板</a>的声明点紧随该别名所代表的类型标识之后:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">using</span> T <span class="sy1">=</span> <span class="kw4">int</span><span class="sy4">;</span> <span class="co1">// T 的声明点在分号处</span>
|
|
<span class="kw1">using</span> T <span class="sy1">=</span> T<span class="sy4">;</span> <span class="co1">// 同 T = int</span></pre></div>
|
|
</div>
|
|
<p>枚举项的声明点紧随其定义之后(而非在初始化器之前,这点不同于变量):</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">const</span> <span class="kw4">int</span> x <span class="sy1">=</span> <span class="nu0">12</span><span class="sy4">;</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw2">enum</span> <span class="br0">{</span>
|
|
x <span class="sy1">=</span> x <span class="sy2">+</span> <span class="nu0">1</span>, <span class="co1">// 声明点在逗号处,x 初始化为 13</span>
|
|
y <span class="sy1">=</span> x <span class="sy2">+</span> <span class="nu0">1</span> <span class="co1">// 枚举项 x 在作用域中,y 初始化为 14</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>不指名构造函数的<a href="cpp-language-using_declaration.html">using 声明</a>内的声明符的声明点紧随该声明符之后:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw4">int</span> N<span class="sy1">></span>
|
|
<span class="kw1">class</span> base <span class="br0">{</span>
|
|
<span class="kw1">protected</span><span class="sy4">:</span>
|
|
<span class="kw4">static</span> <span class="kw4">const</span> <span class="kw4">int</span> next <span class="sy1">=</span> N <span class="sy2">+</span> <span class="nu0">1</span><span class="sy4">;</span>
|
|
<span class="kw4">static</span> <span class="kw4">const</span> <span class="kw4">int</span> value <span class="sy1">=</span> N<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> derived <span class="sy4">:</span> base<span class="sy1"><</span><span class="nu0">0</span><span class="sy1">></span>, base<span class="sy1"><</span><span class="nu0">1</span><span class="sy1">></span>, base<span class="sy1"><</span><span class="nu0">2</span><span class="sy1">></span> <span class="br0">{</span>
|
|
<span class="kw1">using</span> base<span class="sy1"><</span><span class="nu0">0</span><span class="sy1">></span><span class="sy4">::</span><span class="me2">next</span>, <span class="co1">// next 现在在作用域中</span>
|
|
base<span class="sy1"><</span>next<span class="sy1">></span><span class="sy4">::</span><span class="me2">value</span><span class="sy4">;</span> <span class="co1">// derived::value 为 1</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p><a href="cpp-language-injected-class-name.html"><span class="t-spar">注入类名</span></a> 的声明点紧随其类(或类模板)定义的开花括号之后</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">template</span><span class="sy1"><</span><span class="kw1">typename</span> T<span class="sy1">></span>
|
|
<span class="kw1">struct</span> Array
|
|
<span class="co1">// : std::enable_shared_from_this<Array> // 错误:注入类名不在作用域中</span>
|
|
<span class="sy4">:</span> <a href="cpp-memory-enable_shared_from_this.html"><span class="kw744">std::<span class="me2">enable_shared_from_this</span></span></a><span class="sy1"><</span> Array<span class="sy1"><</span>T<span class="sy1">></span> <span class="sy1">></span> <span class="co1">// OK :模板名 Array 在作用域中</span>
|
|
<span class="br0">{</span> <span class="co1">// 注入类名 Array 现在在作用域中,如同为公开成员名</span>
|
|
Array<span class="sy2">*</span> p<span class="sy4">;</span> <span class="co1">// 指向 Array<T> 的指针</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<p>函数局部预定义变量 <span class="t-c"><span class="mw-geshi cpp source-cpp">__func__</span></span> 的声明点紧接函数定义的函数体之前。</p>
|
|
</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-cxx17">
|
|
<td>
|
|
<p><a href="cpp-language-structured_binding.html">结构化绑定</a>的声明点紧随该结构化绑定声明的<span class="t-spar">标识符列表</span>之后,但结构化绑定的初始化器禁止提及其所引入的任何名字。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<p>声明于<a href="cpp-language-range-for.html">基于范围的 for 语句</a>的<span class="t-spar">范围声明</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>之后:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><a href="cpp-container-vector.html"><span class="kw1269">std::<span class="me2">vector</span></span></a><span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span> x<span class="sy4">;</span>
|
|
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">auto</span> x <span class="sy4">:</span> x<span class="br0">)</span> <span class="br0">{</span> <span class="co1">// OK :第二个 x 指代 std::vector<int></span>
|
|
<span class="co1">// 循环体内 x 指代循环变量</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p><a href="cpp-language-template_parameters.html">模板形参</a>的声明点紧随其完整模板形参(包括可选的默认实参)之后:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">typedef</span> <span class="kw4">unsigned</span> <span class="kw4">char</span> T<span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T
|
|
<span class="sy1">=</span> T <span class="co1">// 查找找到 unsigned char 的 typedef 名</span>
|
|
, T <span class="co1">// 查找找到模板形参</span>
|
|
N <span class="sy1">=</span> <span class="nu0">0</span><span class="sy1">></span> <span class="kw1">struct</span> A <span class="br0">{</span> <span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<table class="metadata plainlinks ambox mbox-small-left ambox-notice" style="">
|
|
<tr>
|
|
<td class="mbox-empty-cell"></td>
|
|
<td class="mbox-text" style="">本节未完成<br />
|
|
原因:[basic.scope.pdecl] 的剩余内容</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E5.BC.95.E7.94.A8">引用</span></h3>
|
|
<div class="t-ref-std-c++17">
|
|
<ul>
|
|
<li>C++17 标准(ISO/IEC 14882:2017):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.3 Scope [basic.scope]</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>3.3 Scope [basic.scope]</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>3.3 Scope [basic.scope]</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>3.3 Declarative regions and scopes [basic.scope]</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<table class="t-dsc-begin"></table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|