141 lines
19 KiB
HTML
141 lines
19 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_injected-class-name 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>
|
|
<p>类模板中,注入类名能用作指代当前模板的模板名,或指代当前实例化的类名。</p>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>在类作用域中,当前类的名字被当做它如同是一个公开成员名一样;这被称为<i>注入类名(injected-class-name)</i>。该名字的声明点紧跟类定义的开花括号之后。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">int</span> X<span class="sy4">;</span>
|
|
<span class="kw1">struct</span> X <span class="br0">{</span>
|
|
<span class="kw4">void</span> f<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
X<span class="sy2">*</span> p<span class="sy4">;</span> <span class="co1">// OK:X 指代注入类名</span>
|
|
<span class="sy4">::</span><span class="me2">X</span><span class="sy2">*</span> q<span class="sy4">;</span> <span class="co1">// 错误:名称查找找到变量名,它隐藏结构体名</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</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">struct</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> B <span class="sy4">:</span> <span class="kw1">private</span> A <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> C <span class="sy4">:</span> <span class="kw1">public</span> B <span class="br0">{</span>
|
|
A<span class="sy2">*</span> p<span class="sy4">;</span> <span class="co1">// 错误:注入类名 A 不可访问</span>
|
|
<span class="sy4">::</span><span class="me2">A</span><span class="sy2">*</span> q<span class="sy4">;</span> <span class="co1">// OK:不使用注入类名</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.9C.A8.E7.B1.BB.E6.A8.A1.E6.9D.BF.E4.B8.AD">在类模板中</span></h3>
|
|
<p>与其他类相似,类模板也拥有注入类名。它的注入类名可以被用作模板名或类型名。</p>
|
|
<p>下列情况下,注入类名被当做类模板自身的模板名:</p>
|
|
<ul>
|
|
<li>它后面跟着 <code><b><</b></code></li>
|
|
<li>它被用作对应某个模板模板形参的模板实参</li>
|
|
<li>它是某个友元类模板声明的详述类型说明符中的最后标识符。</li>
|
|
</ul>
|
|
<p>否则,它被当做类型名,并等价于模板名后随环绕于 <code><b><></b></code> 中的该类模板的各个模板形参。</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="kw1">class</span>, <span class="kw1">class</span><span class="sy1">></span> <span class="kw1">class</span><span class="sy1">></span> <span class="kw1">struct</span> A<span class="sy4">;</span>
|
|
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T1, <span class="kw1">class</span> T2<span class="sy1">></span>
|
|
<span class="kw1">struct</span> X <span class="br0">{</span>
|
|
X<span class="sy1"><</span>T1, T2<span class="sy1">></span><span class="sy2">*</span> p<span class="sy4">;</span> <span class="co1">// OK:X 被当做模板名</span>
|
|
<span class="kw1">using</span> a <span class="sy1">=</span> A<span class="sy1"><</span>X<span class="sy1">></span><span class="sy4">;</span> <span class="co1">// OK:X 被当做模板名</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> U1, <span class="kw1">class</span> U2<span class="sy1">></span>
|
|
<span class="kw1">friend</span> <span class="kw1">class</span> X<span class="sy4">;</span> <span class="co1">// OK:X 被当做模板名</span>
|
|
X<span class="sy2">*</span> q<span class="sy4">;</span> <span class="co1">// OK:X 被当做类型名,等价于 X<T1, T2></span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>在类模板特化或部分特化的作用域内,当将注入类名用作类型名时,它等价于模板名后随环绕于 <code><b><></b></code> 中的该类模板特化或部分特化的各个模板实参。</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">struct</span> X<span class="sy1"><</span><span class="kw4">void</span>, <span class="kw4">void</span><span class="sy1">></span> <span class="br0">{</span>
|
|
X<span class="sy2">*</span> p<span class="sy4">;</span> <span class="co1">// OK:X 被当做类型名,等价于 X<void, void></span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span>, <span class="kw1">class</span><span class="sy1">></span>
|
|
<span class="kw1">friend</span> <span class="kw1">class</span> X<span class="sy4">;</span> <span class="co1">// OK:X 被当做模板名(与在模板中相同)</span>
|
|
X<span class="sy1"><</span><span class="kw4">void</span>, <span class="kw4">void</span><span class="sy1">></span><span class="sy2">*</span> q<span class="sy4">;</span> <span class="co1">// OK:X 被当做模板名</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span>
|
|
<span class="kw1">struct</span> X<span class="sy1"><</span><span class="kw4">char</span>, T<span class="sy1">></span> <span class="br0">{</span>
|
|
X<span class="sy2">*</span> p, q<span class="sy4">;</span> <span class="co1">// OK:X 被当做类型名,等价于 X<char, T></span>
|
|
<span class="kw1">using</span> r <span class="sy1">=</span> X<span class="sy1"><</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">></span><span class="sy4">;</span> <span class="co1">// OK:可以用它指名另一特化</span>
|
|
<span class="br0">}</span><span class="sy4">;</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">class</span> X<span class="sy1"><</span><span class="kw4">int</span>, <span class="kw4">char</span><span class="sy1">></span> <span class="br0">{</span>
|
|
<span class="kw1">class</span> B <span class="br0">{</span>
|
|
X a<span class="sy4">;</span> <span class="co1">// 表示 X<int, char></span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span>,<span class="kw1">class</span><span class="sy1">></span> <span class="kw1">friend</span> <span class="kw1">class</span> X<span class="sy4">;</span> <span class="co1">// 表示 ::X</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> <span class="kw1">struct</span> Base <span class="br0">{</span>
|
|
Base<span class="sy2">*</span> p<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> <span class="kw1">struct</span> Derived<span class="sy4">:</span> <span class="kw1">public</span> Base<span class="sy1"><</span>T<span class="sy1">></span> <span class="br0">{</span>
|
|
<span class="kw1">typename</span> Derived<span class="sy4">::</span><span class="me2">Base</span><span class="sy2">*</span> p<span class="sy4">;</span> <span class="co1">// 表示 Derived::Base<T></span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T, <span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span><span class="sy1">></span> <span class="kw1">class</span> U <span class="sy1">=</span> T<span class="sy4">::</span><span class="kw1">template</span> Base<span class="sy1">></span> <span class="kw1">struct</span> Third <span class="br0">{</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
Third<span class="sy1"><</span>Derived<span class="sy1"><</span><span class="kw4">int</span><span class="sy1">>></span> t<span class="sy4">;</span> <span class="co1">// OK:默认实参将注入类名用作模板</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">class</span> T<span class="sy1">></span> <span class="kw1">struct</span> Base <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span> <span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> <span class="kw1">struct</span> Derived<span class="sy4">:</span> Base<span class="sy1"><</span><span class="kw4">int</span><span class="sy1">></span>, Base<span class="sy1"><</span><span class="kw4">char</span><span class="sy1">></span> <span class="br0">{</span>
|
|
<span class="kw1">typename</span> Derived<span class="sy4">::</span><span class="me2">Base</span> b<span class="sy4">;</span> <span class="co1">// 错误:歧义</span>
|
|
<span class="kw1">typename</span> Derived<span class="sy4">::</span><span class="me2">Base</span><span class="sy1"><</span><span class="kw4">double</span><span class="sy1">></span> d<span class="sy4">;</span> <span class="co1">// OK</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E5.85.A5.E7.B1.BB.E5.90.8D.E4.B8.8E.E6.9E.84.E9.80.A0.E5.87.BD.E6.95.B0">注入类名与构造函数</span></h3>
|
|
<p>构造函数没有名字,但在构造函数的声明与定义中,外围类的注入类名被认为是构造函数的名称。</p>
|
|
<p>在有限定的名字 <code>C::D</code> 中,如果</p>
|
|
<ul>
|
|
<li>名字查找不忽略函数名,且</li>
|
|
<li>对 <code>D</code> 在类 <code>C</code> 的作用域中的查找找到了注入类名</li>
|
|
</ul>
|
|
<p>那么始终认为该限定名指名 <code>C</code> 的构造函数。这种名字只能用于构造函数的声明中(例如,在友元构造函数声明,构造函数模板特化,构造函数模板实例化,或构造函数定义中)<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>
|
|
<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="sy4">;</span>
|
|
A<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw1">template</span><span class="sy1"><</span><span class="kw1">class</span> T<span class="sy1">></span> A<span class="br0">(</span>T<span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">using</span> A_alias <span class="sy1">=</span> A<span class="sy4">;</span>
|
|
|
|
A<span class="sy4">::</span><span class="me2">A</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
A_alias<span class="sy4">::</span><span class="me2">A</span><span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
<span class="kw1">template</span> A<span class="sy4">::</span><span class="me2">A</span><span class="br0">(</span><span class="kw4">double</span><span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="kw1">struct</span> B <span class="sy4">:</span> A <span class="br0">{</span>
|
|
<span class="kw1">using</span> A_alias<span class="sy4">::</span><span class="me2">A</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
A<span class="sy4">::</span><span class="me2">A</span> a<span class="sy4">;</span> <span class="co1">// 错误:A::A 被认为指名构造函数,而非类型</span>
|
|
<span class="kw1">struct</span> A<span class="sy4">::</span><span class="me2">A</span> a2<span class="sy4">;</span> <span class="co1">// OK:与 'A a2;' 相同</span>
|
|
B<span class="sy4">::</span><span class="me2">A</span> b<span class="sy4">;</span> <span class="co1">// OK:与 'A b;' 相同</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|