Skip to content

Commit 7e044b2

Browse files
committed
Updated to Chapter 9, Section 4
1 parent 24045db commit 7e044b2

11 files changed

+169
-60
lines changed

Structure.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -661,9 +661,9 @@
661661

662662
> 受保护继承和一些细枝末节的东西都塞到精讲篇。
663663
664-
### 连续继承
664+
### 多级继承
665665

666-
用一些小例子,介绍下连续继承即可
666+
用一些小例子,介绍下多级继承即可
667667

668668
## 继承中的常见问题
669669

generalized_parts/09_class_inheritance/03_private_inheritance.tex

+1-1
Original file line numberDiff line numberDiff line change
@@ -296,4 +296,4 @@ \subsection*{组合方式,还是继承方式?}
296296
\item 在继承方式下,基类的受保护成员对派生类也可见,这就为我们在某些特定条件下写代码提供了便利。
297297
\item 继承方式还为多态提供了可能,我们会在下一节中讲到。
298298
\end{itemize}\par
299-
如果要我描述的话,我认为私有继承相较于组合方式来说,有点像 \lstinline@mutable@ 成员相较于普通成员——如果没有什么这方面的专门需求,就不要用它。总之我是不会在写 \lstinline@Dog@ 类的时候让它继承一个 \lstinline@unsigned@ 类和一个 \lstinline@double@ 类\footnote{一个类可以继承多个基类,这叫作多重继承。我们会在第十章讲解相关内容。},这种没有名字只有类型的事物,光是看上去就很让人困惑了\par
299+
如果要我描述的话,我认为私有继承相较于组合方式来说,有点像 \lstinline@mutable@ 成员相较于普通成员——如果没有什么这方面的专门需求,就不要用它。虽说如此,但是私有继承作为一种行之有效的表示``整体与部分''关系的方式,仍是读者应知应会的内容\par
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
\section{多级继承}
2+
任何一个自定义类型都可以作为基类,被其它类继承,从而成为其它类的一部分。对于公有继承来说,这相当于是对基类对象所拥有的共性,添加了一些派生类对象额外的特性;对于私有继承来说,这相当于是把一个基类的对象内嵌到派生类中,作为它的一个成员。\par
3+
接下来我们还可以把派生类再作为基类,用它来继承新的类。我们把这种操作叫作\textbf{多级继承(Multilevel inheritance)}。
4+
\begin{lstlisting}
5+
struct A { /*...*/ };
6+
struct B : A { /*...*/ }; //B继承自A
7+
struct C : B { /*...*/ }; //C继承自B
8+
class D : C { /*...*/ }; //D继承自C
9+
\end{lstlisting}
10+
看上去好像很复杂,但是读者只需要把握刚才那点就可以理顺各种关系。对于这个继承关系来说,\lstinline@B@ 继承了 \lstinline@A@ 的共性又有自己的特性;\lstinline@C@ 继承了 \lstinline@B@ 的共性并有了自己的特性;\lstinline@D@ 稍有不同,它私有继承自 \lstinline@C@,表示的是 \lstinline@D@ 中内嵌了一个 \lstinline@C@ 对象作为其成员。\par
11+
当然,这是一个虚构的例子,不那么形象。现在我们就来看两个真实的例子。\par
12+
\subsection*{生物分类法}
13+
\begin{figure}[htbp]
14+
\centering
15+
\includegraphics[width=.75\textwidth]{../images/generalized_parts/09_taxonomic_rank_graph_of_red_fox.png}
16+
\caption{赤狐的生物分类}
17+
\footnotesize{图片来源:Wikipedia}
18+
\end{figure}
19+
图9.5是赤狐(Red fox, \textit{Vulpes vulpes})在生物分类法中的位置。它属于真核域Eukaryota - 动物界Animalia - 脊索动物门Chordata - 哺乳纲Mammalia - 食肉目Carnivora - 犬科Canidae - 狐属\textit{Vulpes}。\par
20+
这里面有好复杂的层级,但我们不难看出,它们之间是通过广义的``属与种''关系串连起来的:
21+
\begin{itemize}
22+
\item 狐属是犬科的一种,它既有犬科的共性,又有狐属的独特性——比如蓬松的尾巴;
23+
\item 犬科是食肉目的一种,它既有食肉目的特性,又有犬科的独特性——比如较长的颅骨;
24+
\item ……
25+
\item 动物界是真核域的一种,它既有真核域的特性,又有动物界的独特性——比如运动能力。
26+
\end{itemize}
27+
所以我们可以用一套复杂的公有继承关系来描述生物分类。
28+
\begin{lstlisting}
29+
class Eukarya { //真核域
30+
protected:
31+
class Nucleus { /*...*/ } nucleus; //真核域生物均有细胞核
32+
//...
33+
};
34+
class Animalia : public Eukarya { //动物界,公有继承自真核域
35+
public:
36+
virtual void move(); //动物界生物均有运动能力(我们会在下一章讲virtual)
37+
//...
38+
};
39+
class Chordata : public Animalia { //脊索动物门,公有继承自动物界
40+
protected:
41+
class Notochord { /*...*/ } notochord; //脊索动物门生物均有脊索
42+
};
43+
class Carnivora : public Chordata { //食肉目,公有继承自脊索动物门
44+
//...
45+
};
46+
class Canidae : public Carnivora { //犬科,公有继承自食肉目
47+
//...
48+
};
49+
class Vulpes : public Vulples { //狐属,公有继承自犬科
50+
//...
51+
};
52+
class Vulpes_vulpes : public Vulpes { //赤狐种,公有继承自狐属
53+
//...
54+
};
55+
\end{lstlisting}
56+
像这样,我们就可以通过继承关系建立起一个复杂的树状结构。所以一个赤狐种的对象具有从 \lstinline@Eukarya@ 类到 \lstinline@Vulpes@ 类的所有公有和受保护成员。\par
57+
如果我们还想要添加新的分支类,只需要通过继承关系把它们接到适当的类中,就可以拥有这个类及其基类的全部成员。举个例子说,犬科还有一条分支是犬属\textit{Canis} - 狼种\textit{Canis lupus} - 家犬亚种\textit{Canis lupus familaries}。所以我们可以在 \lstinline@Canidae@ 之下再继承一个分支。
58+
\begin{lstlisting}
59+
class Canis : public Canidae { //犬属,公有继承自犬科
60+
//...
61+
};
62+
class Canis_lupus : public Canis { //狼种,公有继承自犬属
63+
//...
64+
};
65+
class Canis_lupus_familaries : public Canis_lupus { //家犬亚种,公有继承自狼种
66+
//...
67+
};
68+
\end{lstlisting}\par
69+
这样一来,赤狐种 \lstinline@Vulpes_vulpes@ 和家犬亚种 \lstinline@Canis_lupus_familaries@ 就在相同的特怔方面继承同一个类,而在各自的特性上又有自己的一套。就这样,面对这样错综复杂的关系,C++可以通过继承功能,把它们梳理得十分清晰。\par
70+
\subsection*{C++流输入/输出库}
71+
C++的流输入/输出库是一个系统,包含 \lstinline@iostream@, \lstinline@fstream@, \lstinline@sstream@ 等许多库文件,\lstinline@std::istream@, \lstinline@std::ostream@ 等许多我们已经熟知的类模版或类。它们之间有一套复杂的继承关系,见图9.6。其中,\lstinline@std::istream@ 是 \lstinline@std::basic_istream@ 类模版的一个实例,定义为 \lstinline@std::basic_istream<char>@;\lstinline@std::ostream@ 是 \lstinline@std::basic_ostream@ 类模版的一个实例,定义为 \lstinline@std::basic_ostream<char>@。\par
72+
\begin{figure}[htbp]
73+
\centering
74+
\includegraphics[width=.8\textwidth]{../images/generalized_parts/09_inheritance_diagram_of_io_library.png}
75+
\caption{C++流输入/输出库中的继承关系}
76+
\end{figure}
77+
我们曾经用 \lstinline@std::cout.setf(std::ios_base::boolalpha)@ 来改变 \lstinline@std::cout@ 对 \lstinline@bool@ 数据的输出方式,这里的 \lstinline@setf@ 和 \lstinline@fmtflags@ 其实都是定义在 \lstinline@std::ios_base@ 类中的。\lstinline@std::ostream@ 间接继承了 \lstinline@std::ios_base@ 类,所以它可以把 \lstinline@std::ios_base::setf@ 当作自己的成员函数来调用。\par
78+
我们也曾用过 \lstinline@std::cin.clear()@ 这样的写法,这里的 \lstinline@clear@ 是定义在 \lstinline@std::basic_ios<CharT,Traits>@ 类中的一个成员函数。\lstinline@std::istream@ 类继承了 \lstinline@std::basic_ios<ChatT,Traits>@,所以它也能调用这个成员函数。\par
79+
敏锐的读者可能发现了,图9.6中的 \lstinline@std::basic_iostream@ 类同时继承了 \lstinline@std::basic_ostream@ 和 \lstinline@std::basic_istream@ 类。这种操作叫作多重继承,我们会在第十章中讲解有关问题。\par
Loading
Loading

main.aux

+25-22
Original file line numberDiff line numberDiff line change
@@ -184,19 +184,22 @@
184184
\@writefile{lof}{\contentsline {figure}{\numberline {9.3}{\ignorespaces 一个派生类对象当中内嵌了一个基类对象}}{245}{figure.9.3}\protected@file@percent }
185185
\@writefile{toc}{\contentsline {section}{\numberline {9.3}私有继承}{248}{section.9.3}\protected@file@percent }
186186
\@writefile{lof}{\contentsline {figure}{\numberline {9.4}{\ignorespaces 栈的数据操作方式:从末端堆入、从末端移出}}{251}{figure.9.4}\protected@file@percent }
187+
\@writefile{toc}{\contentsline {section}{\numberline {9.4}多级继承}{255}{section.9.4}\protected@file@percent }
188+
\@writefile{lof}{\contentsline {figure}{\numberline {9.5}{\ignorespaces 赤狐的生物分类}}{256}{figure.9.5}\protected@file@percent }
189+
\@writefile{lof}{\contentsline {figure}{\numberline {9.6}{\ignorespaces C++流输入/输出库中的继承关系}}{258}{figure.9.6}\protected@file@percent }
187190
\gdef \LT@i {\LT@entry
188191
{1}{42.00002pt}\LT@entry
189192
{1}{136.19997pt}\LT@entry
190193
{1}{117.00002pt}\LT@entry
191194
{1}{52.00002pt}\LT@entry
192195
{1}{82.00002pt}}
193-
\@writefile{toc}{\contentsline {part}{精讲篇}{259}{part*.181}\protected@file@percent }
194-
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 A\hspace {.3em}}C++运算符基本属性}{259}{appendix.A}\protected@file@percent }
196+
\@writefile{toc}{\contentsline {part}{精讲篇}{261}{part*.183}\protected@file@percent }
197+
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 A\hspace {.3em}}C++运算符基本属性}{261}{appendix.A}\protected@file@percent }
195198
\@writefile{lof}{\addvspace {10.0pt}}
196199
\@writefile{lot}{\addvspace {10.0pt}}
197-
\newlabel{ch:appendix_A}{{A}{259}{C++运算符基本属性}{appendix.A}{}}
198-
\@writefile{lot}{\contentsline {table}{\numberline {A.1}{截至C++17的所有运算符}}{259}{table.A.1}\protected@file@percent }
199-
\newlabel{tab:A-1}{{A.1}{259}{截至C++17的所有运算符}{table.A.1}{}}
200+
\newlabel{ch:appendix_A}{{A}{261}{C++运算符基本属性}{appendix.A}{}}
201+
\@writefile{lot}{\contentsline {table}{\numberline {A.1}{截至C++17的所有运算符}}{261}{table.A.1}\protected@file@percent }
202+
\newlabel{tab:A-1}{{A.1}{261}{截至C++17的所有运算符}{table.A.1}{}}
200203
\gdef \LT@ii {\LT@entry
201204
{1}{33.67001pt}\LT@entry
202205
{1}{33.81001pt}\LT@entry
@@ -208,11 +211,11 @@
208211
{1}{26.72002pt}\LT@entry
209212
{1}{27.283pt}\LT@entry
210213
{1}{86.44002pt}}
211-
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 B\hspace {.3em}}ASCII码表(0到127)}{261}{appendix.B}\protected@file@percent }
214+
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 B\hspace {.3em}}ASCII码表(0到127)}{263}{appendix.B}\protected@file@percent }
212215
\@writefile{lof}{\addvspace {10.0pt}}
213216
\@writefile{lot}{\addvspace {10.0pt}}
214-
\@writefile{lot}{\contentsline {table}{\numberline {B.1}{33个ASCII控制字符}}{261}{table.B.1}\protected@file@percent }
215-
\newlabel{tab:B-1}{{B.1}{261}{33个ASCII控制字符}{table.B.1}{}}
217+
\@writefile{lot}{\contentsline {table}{\numberline {B.1}{33个ASCII控制字符}}{263}{table.B.1}\protected@file@percent }
218+
\newlabel{tab:B-1}{{B.1}{263}{33个ASCII控制字符}{table.B.1}{}}
216219
\gdef \LT@iii {\LT@entry
217220
{1}{33.67001pt}\LT@entry
218221
{1}{33.81001pt}\LT@entry
@@ -226,19 +229,19 @@
226229
{1}{33.67001pt}\LT@entry
227230
{1}{33.81001pt}\LT@entry
228231
{1}{26.72002pt}}
229-
\@writefile{lot}{\contentsline {table}{\numberline {B.2}{95个ASCII可打印字符}}{262}{table.B.2}\protected@file@percent }
230-
\newlabel{tab:B-2}{{B.2}{262}{95个ASCII可打印字符}{table.B.2}{}}
231-
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 C\hspace {.3em}}相关数学知识}{263}{appendix.C}\protected@file@percent }
232+
\@writefile{lot}{\contentsline {table}{\numberline {B.2}{95个ASCII可打印字符}}{264}{table.B.2}\protected@file@percent }
233+
\newlabel{tab:B-2}{{B.2}{264}{95个ASCII可打印字符}{table.B.2}{}}
234+
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 C\hspace {.3em}}相关数学知识}{265}{appendix.C}\protected@file@percent }
232235
\@writefile{lof}{\addvspace {10.0pt}}
233236
\@writefile{lot}{\addvspace {10.0pt}}
234-
\@writefile{toc}{\contentsline {section}{\numberline {C.1}数制转换}{263}{section.C.1}\protected@file@percent }
235-
\@writefile{lof}{\contentsline {figure}{\numberline {C.1}{\ignorespaces 一个简单的数字时钟}}{263}{figure.C.1}\protected@file@percent }
236-
\@writefile{lof}{\contentsline {figure}{\numberline {C.2}{\ignorespaces 从计数到乘方}}{264}{figure.C.2}\protected@file@percent }
237-
\@writefile{lof}{\contentsline {figure}{\numberline {C.3}{\ignorespaces 一个12进制乘法表}}{265}{figure.C.3}\protected@file@percent }
238-
\@writefile{lof}{\contentsline {figure}{\numberline {C.4}{\ignorespaces $(1a.c3)_{16}$的形式化表示}}{267}{figure.C.4}\protected@file@percent }
239-
\@writefile{lof}{\contentsline {figure}{\numberline {C.5}{\ignorespaces 通过短除法把十进制数转换成$R$进制}}{270}{figure.C.5}\protected@file@percent }
240-
\@writefile{lof}{\contentsline {figure}{\numberline {C.6}{\ignorespaces 二进制与八进制的转换}}{271}{figure.C.6}\protected@file@percent }
241-
\@writefile{lof}{\contentsline {figure}{\numberline {C.7}{\ignorespaces 二进制与十六进制的转换}}{272}{figure.C.7}\protected@file@percent }
242-
\@writefile{toc}{\contentsline {section}{\numberline {C.2}布尔代数基础}{272}{section.C.2}\protected@file@percent }
243-
\@writefile{toc}{\contentsline {chapter}{跋}{273}{appendix*.189}\protected@file@percent }
244-
\gdef \@abspage@last{280}
237+
\@writefile{toc}{\contentsline {section}{\numberline {C.1}数制转换}{265}{section.C.1}\protected@file@percent }
238+
\@writefile{lof}{\contentsline {figure}{\numberline {C.1}{\ignorespaces 一个简单的数字时钟}}{265}{figure.C.1}\protected@file@percent }
239+
\@writefile{lof}{\contentsline {figure}{\numberline {C.2}{\ignorespaces 从计数到乘方}}{266}{figure.C.2}\protected@file@percent }
240+
\@writefile{lof}{\contentsline {figure}{\numberline {C.3}{\ignorespaces 一个12进制乘法表}}{267}{figure.C.3}\protected@file@percent }
241+
\@writefile{lof}{\contentsline {figure}{\numberline {C.4}{\ignorespaces $(1a.c3)_{16}$的形式化表示}}{269}{figure.C.4}\protected@file@percent }
242+
\@writefile{lof}{\contentsline {figure}{\numberline {C.5}{\ignorespaces 通过短除法把十进制数转换成$R$进制}}{272}{figure.C.5}\protected@file@percent }
243+
\@writefile{lof}{\contentsline {figure}{\numberline {C.6}{\ignorespaces 二进制与八进制的转换}}{273}{figure.C.6}\protected@file@percent }
244+
\@writefile{lof}{\contentsline {figure}{\numberline {C.7}{\ignorespaces 二进制与十六进制的转换}}{274}{figure.C.7}\protected@file@percent }
245+
\@writefile{toc}{\contentsline {section}{\numberline {C.2}布尔代数基础}{274}{section.C.2}\protected@file@percent }
246+
\@writefile{toc}{\contentsline {chapter}{跋}{275}{appendix*.191}\protected@file@percent }
247+
\gdef \@abspage@last{282}

0 commit comments

Comments
 (0)