245 lines
34 KiB
HTML
245 lines
34 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_derived_class 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>任何类类型(无论是以 <span class="t-spar">类关键词</span> <code>class</code> 还是 <code>struct</code> 声明)均可被声明为<i>派生于</i>一个或多个<i>基类</i>,各基类也可以派生自其自身的基类,组成继承层级结构。</p>
|
|
<p>基类的列表在<a href="cpp-language-class.html">类声明语法</a>的 <span class="t-spar">基类子句</span> 中提供。<span class="t-spar">基类子句</span> 由字符 <code><b>:</b></code> 后随一或多个 <span class="t-spar">基类说明符</span> 的逗号分隔列表组成。</p>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td class="t-sdsc-nopad"><span class="t-spar">属性</span><span class="t-mark">(可选)</span> <span class="t-spar">访问说明符</span><span class="t-mark">(可选)</span> <span class="t-spar">虚说明符</span><span class="t-mark">(可选)</span> <span class="t-spar">类或-decltype</span></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<table class="t-par-begin">
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">属性</span></td>
|
|
<td>-</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span> 可选的任意数量<a href="cpp-language-attributes.html">属性</a>的序列</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">访问说明符</span></td>
|
|
<td>-</td>
|
|
<td><code>private</code>、<code>public</code> 或 <code>protected</code> 之一</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">虚说明符</span></td>
|
|
<td>-</td>
|
|
<td>关键词 <code>virtual</code></td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">类或-decltype</span></td>
|
|
<td>-</td>
|
|
<td>以下之一:
|
|
<ul>
|
|
<li><span class="t-spar">嵌套名说明符</span><span class="t-mark">(可选)</span> <span class="t-spar">类型名</span></li>
|
|
<li><span class="t-spar">嵌套名说明符</span> <code><b>template</b></code> <span class="t-spar">简单模板标识</span></li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<ul>
|
|
<li><a href="cpp-language-decltype.html"><span class="t-spar">decltype-说明符</span></a></li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<p><span class="t-spar">虚说明符</span> 与 <span class="t-spar">访问说明符</span> 可以以任意顺序出现。由于语法限制,<a href="cpp-language-elaborated_type_specifier.html">详述类型说明符</a>不能直接作为 <span class="t-spar">类或-decltype</span> 出现。</p>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<p><span class="t-spar">基类子句</span> 中的 <span class="t-spar">基类说明符</span> 可以是<a href="cpp-language-parameter_pack.html">包展开</a>。</p>
|
|
<p><span class="t-spar">类或-decltype</span> 不能指代声明为 <a href="cpp-language-final.html"><code>final</code></a> 的类或结构体。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>如果省略 <span class="t-spar">访问说明符</span>,那么它对以 <span class="t-spar">类关键词</span> <code>struct</code> 声明的类默认为 <code>public</code>,对以 <span class="t-spar">类关键词</span> <code>class</code> 声明的类为 <code>private</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> Base <span class="br0">{</span>
|
|
<span class="kw4">int</span> a, b, c<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// 每个 Derived 类型对象包含一个 Base 子对象</span>
|
|
<span class="kw1">struct</span> Derived <span class="sy4">:</span> Base <span class="br0">{</span>
|
|
<span class="kw4">int</span> b<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// 每个 Derived2 类型对象包含 Derived 与 Base 子对象</span>
|
|
<span class="kw1">struct</span> Derived2 <span class="sy4">:</span> Derived <span class="br0">{</span>
|
|
<span class="kw4">int</span> c<span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>在 <span class="t-spar">基类子句</span> 中列出的 <span class="t-spar">类或-decltype</span> 所指代的类是直接基类。它们的基类是间接基类。同一类不能被多次指定为直接基类,但同一类可以既是直接又是间接基类。</p>
|
|
<p>每个直接和间接基类都作为<i>基类子对象</i>,以依赖于 ABI 的偏移量存在于派生类的对象表示中。因为<a href="cpp-language-ebo.html">空基类优化</a>,空基类通常不会增加派生类对象的大小。基类子对象的构造函数被派生类的构造函数所调用:可以在<a href="cpp-language-initializer_list.html" class="mw-redirect">成员初始化器列表</a>中向这些构造函数提供实参。</p>
|
|
<h3><span class="mw-headline" id=".E8.99.9A.E5.9F.BA.E7.B1.BB">虚基类</span></h3>
|
|
<p>对于每个指定为 <code>virtual</code> 的不同基类,最终派生对象中仅含有该类型的一个基类子对象,即使该类在继承层级中出现多次也是如此(只要它每次都以 <code>virtual</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> B <span class="br0">{</span> <span class="kw4">int</span> n<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">class</span> X <span class="sy4">:</span> <span class="kw1">public</span> <span class="kw1">virtual</span> B <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">class</span> Y <span class="sy4">:</span> <span class="kw1">virtual</span> <span class="kw1">public</span> B <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">class</span> Z <span class="sy4">:</span> <span class="kw1">public</span> B <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// 每个 AA 类型对象拥有一个 X,一个 Y,一个 Z 和两个 B:</span>
|
|
<span class="co1">// 一个是 Z 的基类,另一个由 X 与 Y 所共享</span>
|
|
<span class="kw1">struct</span> AA <span class="sy4">:</span> X, Y, Z <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="sy4">::</span><span class="me2">n</span> <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// 修改虚 B 子对象的成员</span>
|
|
Y<span class="sy4">::</span><span class="me2">n</span> <span class="sy1">=</span> <span class="nu0">2</span><span class="sy4">;</span> <span class="co1">// 修改同一虚 B 子对象的成员</span>
|
|
Z<span class="sy4">::</span><span class="me2">n</span> <span class="sy1">=</span> <span class="nu0">3</span><span class="sy4">;</span> <span class="co1">// 修改非虚 B 子对象的成员</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="sy4">::</span><span class="me2">n</span> <span class="sy1"><<</span> Y<span class="sy4">::</span><span class="me2">n</span> <span class="sy1"><<</span> Z<span class="sy4">::</span><span class="me2">n</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// 打印 223</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
<p>继承层级有虚基类的例子之一是标准库的 iostream 的继承层级:<span class="t-lc"><a href="cpp-io-basic_istream.html">std::istream</a></span> 与 <span class="t-lc"><a href="cpp-io-basic_ostream.html">std::ostream</a></span> 使用虚继承从 <span class="t-lc"><a href="cpp-io-basic_ios.html">std::ios</a></span> 派生。<span class="t-lc"><a href="cpp-io-basic_iostream.html">std::iostream</a></span> 同时派生于 <span class="t-lc"><a href="cpp-io-basic_istream.html">std::istream</a></span> 和 <span class="t-lc"><a href="cpp-io-basic_ostream.html">std::ostream</a></span>,所以每个 <span class="t-lc"><a href="cpp-io-basic_iostream.html">std::iostream</a></span> 实例含有一个 <span class="t-lc"><a href="cpp-io-basic_ostream.html">std::ostream</a></span> 子对象、一个 <span class="t-lc"><a href="cpp-io-basic_istream.html">std::istream</a></span> 子对象和只有一个 <span class="t-lc"><a href="cpp-io-basic_ios.html">std::ios</a></span> 子对象(因此也只有一个 <span class="t-lc"><a href="cpp-io-ios_base.html">std::ios_base</a></span>)。</p>
|
|
<p>所有虚基类子对象都在任何非虚基类子对象之前初始化,所以只有最终派生类会在它的<a href="cpp-language-initializer_list.html" 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> B <span class="br0">{</span>
|
|
<span class="kw4">int</span> n<span class="sy4">;</span>
|
|
B<span class="br0">(</span><span class="kw4">int</span> x<span class="br0">)</span> <span class="sy4">:</span> n<span class="br0">(</span>x<span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> X <span class="sy4">:</span> <span class="kw1">virtual</span> B <span class="br0">{</span> X<span class="br0">(</span><span class="br0">)</span> <span class="sy4">:</span> B<span class="br0">(</span><span class="nu0">1</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> Y <span class="sy4">:</span> <span class="kw1">virtual</span> B <span class="br0">{</span> Y<span class="br0">(</span><span class="br0">)</span> <span class="sy4">:</span> B<span class="br0">(</span><span class="nu0">2</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> AA <span class="sy4">:</span> X, Y <span class="br0">{</span> AA<span class="br0">(</span><span class="br0">)</span> <span class="sy4">:</span> B<span class="br0">(</span><span class="nu0">3</span><span class="br0">)</span>, X<span class="br0">(</span><span class="br0">)</span>, Y<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><span class="br0">}</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// AA 的默认构造函数调用 X 和 Y 的默认构造函数</span>
|
|
<span class="co1">// 但这些构造函数不调用 B 的构造函数,因为 B 是虚基类</span>
|
|
AA a<span class="sy4">;</span> <span class="co1">// a.n == 3</span>
|
|
<span class="co1">// X 的默认构造函数调用 B 的构造函数</span>
|
|
X x<span class="sy4">;</span> <span class="co1">// x.n == 1</span></pre></div>
|
|
</div>
|
|
<p>涉及虚继承时,对类成员的无限定名字查找有<a href="cpp-language-unqualified_lookup.html#.E6.88.90.E5.91.98.E5.87.BD.E6.95.B0.E7.9A.84.E5.AE.9A.E4.B9.89">特殊规则</a>(有时被称为“优先性(dominance)规则”)。</p>
|
|
<h3><span class="mw-headline" id=".E5.85.AC.E5.BC.80.E7.BB.A7.E6.89.BF">公开继承</span></h3>
|
|
<p>当类使用 <code>public</code> <a href="cpp-language-access.html">成员访问说明符</a>从基类派生时,基类的所有公开成员可作为派生类的公开成员访问,基类的所有受保护成员可作为派生类的受保护成员访问(基类的私有成员始终不可访问,除非设为友元)。</p>
|
|
<p>公开继承塑造了面向对象编程的子类型关系:派生类对象是(IS-A)基类对象。到派生类对象的引用和指针,可被期待到其任何公开基类的引用和指针的代码所用(见 <a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle" class="extiw" title="enwiki:Liskov substitution principle">LSP</a>),或者以 <a href="https://en.wikipedia.org/wiki/Design_by_contract" class="extiw" title="enwiki:Design by contract">DbC</a> 的说法,派生类应该维护其公开基类的类不变式,不应强化其所<a href="cpp-language-virtual.html">覆盖</a>的成员函数的任何前条件,或弱化其任何后条件。</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 <vector></span>
|
|
<span class="co2">#include <string></span>
|
|
<span class="co2">#include <iostream></span>
|
|
|
|
<span class="kw1">struct</span> MenuOption <span class="br0">{</span> <a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> title<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// Menu 是 MenuOption 的 vector :能插入、移除、重排……选项并拥有标题。</span>
|
|
<span class="kw1">class</span> Menu <span class="sy4">:</span> <span class="kw1">public</span> <a href="cpp-container-vector.html"><span class="kw1269">std::<span class="me2">vector</span></span></a><span class="sy1"><</span>MenuOption<span class="sy1">></span> <span class="br0">{</span>
|
|
<span class="kw1">public</span><span class="sy4">:</span>
|
|
<a href="cpp-string-basic_string.html"><span class="kw1230">std::<span class="me2">string</span></span></a> title<span class="sy4">;</span>
|
|
|
|
<span class="kw4">void</span> print<span class="br0">(</span><span class="br0">)</span> <span class="kw4">const</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> title <span class="sy1"><<</span> <span class="st0">":<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> i <span class="sy1">=</span> <span class="nu0">0</span>, s <span class="sy1">=</span> size<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> i <span class="sy1"><</span> s<span class="sy4">;</span> <span class="sy2">++</span>i<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> <span class="st0">" "</span> <span class="sy1"><<</span> <span class="br0">(</span>i<span class="sy2">+</span><span class="nu0">1</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">". "</span> <span class="sy1"><<</span> at<span class="br0">(</span>i<span class="br0">)</span>.<span class="me1">title</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// 注: Menu::title 没有问题因为它的角色与基类独立。</span>
|
|
|
|
<span class="kw2">enum</span> <span class="kw1">class</span> Color <span class="br0">{</span> WHITE, RED, BLUE, GREEN <span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">void</span> apply_terminal_color<span class="br0">(</span>Color<span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/* 操作系统特定 */</span> <span class="br0">}</span>
|
|
|
|
<span class="co1">// 这不好!</span>
|
|
<span class="co1">// ColorMenu 是每个选项都有定制颜色的 Menu 。</span>
|
|
<span class="kw1">class</span> ColorMenu <span class="sy4">:</span> <span class="kw1">public</span> Menu <span class="br0">{</span>
|
|
<span class="kw1">public</span><span class="sy4">:</span>
|
|
<a href="cpp-container-vector.html"><span class="kw1269">std::<span class="me2">vector</span></span></a><span class="sy1"><</span>Color<span class="sy1">></span> colors<span class="sy4">;</span>
|
|
|
|
<span class="kw4">void</span> print<span class="br0">(</span><span class="br0">)</span> <span class="kw4">const</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> title <span class="sy1"><<</span> <span class="st0">":<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><a href="cpp-types-size_t.html"><span class="kw100">std::<span class="me2">size_t</span></span></a> i <span class="sy1">=</span> <span class="nu0">0</span>, s <span class="sy1">=</span> size<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> i <span class="sy1"><</span> s<span class="sy4">;</span> <span class="sy2">++</span>i<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> <span class="st0">" "</span> <span class="sy1"><<</span> <span class="br0">(</span>i<span class="sy2">+</span><span class="nu0">1</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">". "</span><span class="sy4">;</span>
|
|
apply_terminal_color<span class="br0">(</span>colors<span class="br0">[</span>i<span class="br0">]</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> at<span class="br0">(</span>i<span class="br0">)</span>.<span class="me1">title</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
apply_terminal_color<span class="br0">(</span>Color<span class="sy4">::</span><span class="me2">WHITE</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// ColorMenu 需要下列通过公开继承 Menu 无法满足的不变式,例如:</span>
|
|
<span class="co1">// - ColorMenu::colors 与 Menu 必须拥有相同数量的元素</span>
|
|
<span class="co1">// - 为使得有意义,调用 erase() 也应该从 colors 移除元素以保持选项颜色</span>
|
|
<span class="co1">// 基本上每个对 std::vector 的非 const 方法调用都会破坏 ColorMenu 的不变式</span>
|
|
<span class="co1">// 并将会需要从用户由正确管理颜色来修复。</span>
|
|
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
ColorMenu color_menu<span class="sy4">;</span>
|
|
|
|
<span class="co1">// 这个类的大问题是我们必须保持_Color 与的 Menu 同步。</span>
|
|
color_menu.<span class="me1">push_back</span><span class="br0">(</span>MenuOption<span class="br0">{</span><span class="st0">"某些选择"</span><span class="br0">}</span><span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// color_menu.print(); // 错误!print() 中的 colors[i] 在范围外</span>
|
|
|
|
color_menu.<span class="me1">colors</span>.<span class="me1">push_back</span><span class="br0">(</span>Color<span class="sy4">::</span><span class="me2">RED</span><span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
color_menu.<span class="me1">print</span><span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK :colors 与 Menu 拥有相同的元素数</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.97.E4.BF.9D.E6.8A.A4.E7.BB.A7.E6.89.BF">受保护继承</span></h3>
|
|
<p>当类使用 <code>protected</code> <a href="cpp-language-access.html">成员访问说明符</a>从基类派生时,基类的所有公开和受保护成员可作为派生类的受保护成员访问(基类的私有成员始终不可访问,除非设为友元)。</p>
|
|
<p>受保护继承可用于“受控制的多态”:在派生类的成员中,以及所有进一步派生的类的成员中,派生类是(IS-A)基类:到派生类的引用和指针可用于期待到基类的引用和指针处。</p>
|
|
<h3><span class="mw-headline" id=".E7.A7.81.E6.9C.89.E7.BB.A7.E6.89.BF">私有继承</span></h3>
|
|
<p>当类使用 <code>private</code> <a href="cpp-language-access.html">成员访问说明符</a>从基类派生时,基类的所有公开和受保护成员可作为派生类的私有成员访问(基类的私有成员始终不可访问,除非设为友元)。</p>
|
|
<p>私有继承常用于基于策略的设计,因为策略常是空基类,而使用基类可以同时启用静多态并活用<a href="cpp-language-ebo.html">空基类优化</a></p>
|
|
<p>私有继承也可以用于实现合成关系(基类子对象是派生类对象的实现细节)。除非派生类需要访问基类的受保护成员(包含构造函数),需要覆盖基类的虚成员,需要基类在某个其他基类子对象之前构造或在其之后销毁,需要共享虚基类或需要控制虚基类的构造,否则使用成员方案可以提供更好的封装,而且通常是更受偏好的方式。使用成员来实现合成关系,亦不适用于从<a href="cpp-language-parameter_pack.html">参数包</a>进行多重继承的情况,或在编译时通过模板元编程确定各基类身份的情况。</p>
|
|
<p>与受保护继承相似,私有继承也可以用于受控制的多态:在派生类的成员内(但不在进一步派生的类中),派生类是(IS-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> Transport<span class="sy1">></span>
|
|
<span class="kw1">class</span> service <span class="sy4">:</span> <span class="kw1">private</span> Transport <span class="co1">// 从 Transport 策略私有继承</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">public</span><span class="sy4">:</span>
|
|
<span class="kw4">void</span> transmit<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
|
|
this<span class="sy2">-</span><span class="sy1">></span>send<span class="br0">(</span>...<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 使用 Transport 提供的任何东西进行发送</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// TCP 传输策略</span>
|
|
<span class="kw1">class</span> tcp <span class="br0">{</span>
|
|
<span class="kw1">public</span><span class="sy4">:</span>
|
|
<span class="kw4">void</span> send<span class="br0">(</span>...<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="co1">// UDP 传输策略</span>
|
|
<span class="kw1">class</span> udp <span class="br0">{</span>
|
|
<span class="kw1">public</span><span class="sy4">:</span>
|
|
<span class="kw4">void</span> send<span class="br0">(</span>...<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span><span class="sy4">;</span>
|
|
|
|
service<span class="sy1"><</span>tcp<span class="sy1">></span> service<span class="br0">(</span>host, port<span class="br0">)</span><span class="sy4">;</span>
|
|
service.<span class="me1">transmit</span><span class="br0">(</span>...<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 通过 TCP 发送</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E6.88.90.E5.91.98.E5.90.8D.E5.AD.97.E6.9F.A5.E6.89.BE">成员名字查找</span></h3>
|
|
<p>针对类成员进行的无限定和有限定的名字查找规则,详见于<a href="cpp-language-lookup.html">名字查找</a>。</p>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<ul>
|
|
<li><a href="cpp-language-virtual.html">虚函数</a></li>
|
|
<li><a href="cpp-language-abstract_class.html">抽象类</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|