⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 item_022.htm

📁 C++程序编写规范,适合C++中级读者
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>不要相互依赖:循环依赖发生在两个模块直接或间接地依赖于另一个时。模块是一个内聚的发布单元(参见第</span><span
lang=EN-US style='font-size:12.0pt'>103</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>页),相互依赖的模块不是真正的独立的模块,而是粘在一起的一个更大的模块,一个更大的发布单元。因此,循环依赖性对模块化无益,是大型项目的祸根。要避免它们。</span><span
lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>讨论</span></b><b style='mso-bidi-font-weight:
normal'><span lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></b></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>除非确实需要一个类型的定义,否则应该优先使用前置声明。在两种情况下需要</span><span
lang=EN-US style='font-size:12.0pt'>class C</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>的完整定义:</span><span lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='margin-left:42.0pt;text-indent:-21.0pt;mso-list:l0 level1 lfo1;
tab-stops:list 42.0pt'><![if !supportLists]><span lang=EN-US style='font-size:
12.0pt;font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings'><span style='mso-list:Ignore'>l<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]><span style='font-size:12.0pt;font-family:宋体;
mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>需要知道</span><span
lang=EN-US style='font-size:12.0pt'>C</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>的对象大小:例如,在栈上分配</span><span lang=EN-US style='font-size:12.0pt'>C</span><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>对象,或将</span><span lang=EN-US
style='font-size:12.0pt'>C</span><span style='font-size:12.0pt;font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>作为另一个类型的直接(即:不是指针)成员。</span><span
lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:21.0pt'><span lang=EN-US
style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='margin-left:42.0pt;text-indent:-21.0pt;mso-list:l0 level1 lfo1;
tab-stops:list 42.0pt'><![if !supportLists]><span lang=EN-US style='font-size:
12.0pt;font-family:Wingdings;mso-fareast-font-family:Wingdings;mso-bidi-font-family:
Wingdings'><span style='mso-list:Ignore'>l<span style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></span></span><![endif]><span style='font-size:12.0pt;font-family:宋体;
mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>需要访问或调用</span><span
lang=EN-US style='font-size:12.0pt'>C</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>的成员:例如,调用一个成员函数。</span><span lang=EN-US style='font-size:
12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>与本书的宗旨相一致,我们一开始就把那些会导致编译错误的循环依赖性排除在外,遵循本书以及第</span><span
lang=EN-US style='font-size:12.0pt'>1</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>条中给出的忠告,你应该已经修正了此类错误。所以我们集中精力讨论剩下的那些可编译的代码,看它们是如何损害代码质量的,以及需要采取哪些步骤来避免它们。</span><span
lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>一般来说,依赖性以及循环依赖性应该在模块一层考虑。一个模块是一个内聚的集合,该集合包含了多个一起发布的类和函数(参见第</span><span
lang=EN-US style='font-size:12.0pt'>5</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>条和第</span><span lang=EN-US style='font-size:12.0pt'>103</span><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>页)。循环依赖的最简单形式就是两个类直接相互依赖:</span><span
lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='margin-left:21.0pt;tab-stops:171.0pt'><span
lang=EN-US style='font-size:12.0pt;font-family:"Arial Black"'>class Child;<span
style='mso-tab-count:1'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><i
style='mso-bidi-font-style:normal'><span lang=EN-US style='font-size:12.0pt'>//
</span></i><i style='mso-bidi-font-style:normal'><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>打破循环依赖性</span></i><span lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:21.0pt'><span class=GramE><span
lang=EN-US style='font-size:12.0pt'>class</span></span><span lang=EN-US
style='font-size:12.0pt'> Parent {<i style='mso-bidi-font-style:normal'>// …</i><o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:21.0pt'><span lang=EN-US
style='font-size:12.0pt'><span style='mso-spacerun:yes'>&nbsp; </span>Child*
myChild_;<o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:21.0pt'><span lang=EN-US
style='font-size:12.0pt'>};<o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:21.0pt;tab-stops:171.0pt'><span
class=GramE><span lang=EN-US style='font-size:12.0pt'>class</span></span><span
lang=EN-US style='font-size:12.0pt'> Child {<i style='mso-bidi-font-style:normal'>//
…<span style='mso-tab-count:1'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//
</i></span><i style='mso-bidi-font-style:normal'><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>可能在另一个头文件中</span></i><span lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:21.0pt'><span lang=EN-US
style='font-size:12.0pt'><span style='mso-spacerun:yes'>&nbsp; </span>Parent*
myParent_;<o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:21.0pt'><span lang=EN-US
style='font-size:12.0pt'>};<o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'>Parent</span><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>和</span><span lang=EN-US
style='font-size:12.0pt'>Child</span><span style='font-size:12.0pt;font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>相互依赖。代码可以编译,但我们已经为一个基本的问题搭好了舞台:这两个类再也不是独立的了,而是相互依赖的。这并不一定就有害,但是这种情况应该仅出现在两个类都属于同一模块(由同一个人或小组开发并测试,并作为一个整体发布)时。</span><span
lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>相反,请考虑:如果</span><span
lang=EN-US style='font-size:12.0pt'>Child</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>不需要存储一个指向</span><span lang=EN-US style='font-size:12.0pt'>Parent</span><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>对象的反向链接又如何呢?这样</span><span lang=EN-US
style='font-size:12.0pt'>Child</span><span style='font-size:12.0pt;font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>就可以独自作为一个更小的模块(可能以一个不同的名字)发布,它与</span><span
lang=EN-US style='font-size:12.0pt'>Parent</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>完全无关。这显然是一种更为灵活的设计。</span><span lang=EN-US style='font-size:
12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>当循环依赖性跨越多个模块时,事情只会变得更糟,这些模块被循环依赖性粘在一起,形成了一个巨大的发布单元。这就是为什么循环依赖性是模块化最可怕的敌人。</span><span
lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>为了打破循环依赖性,可以应用</span><span
lang=EN-US style='font-size:12.0pt'>[Martin96a]</span><span style='font-size:
12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>及</span><span lang=EN-US style='font-size:12.0pt'>[Martin00]</span><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>(同时请参见第</span><span lang=EN-US
style='font-size:12.0pt'>36</span><span style='font-size:12.0pt;font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>条)中所述的依赖倒置原则(</span><span
lang=EN-US style='font-size:12.0pt'>Dependency Inversion Principle</span><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>):不要使高层的模块依赖于低层的模块;应该使它们都依赖于抽象。如果你可以为</span><span
lang=EN-US style='font-size:12.0pt'>Parent</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>和</span><span lang=EN-US style='font-size:12.0pt'>Child</span><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>都单独定义各自的抽象,那么你就可以打破循环依赖性。否则,你必须保证让它们属于同一个模块。</span><span
lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>某些特定的设计受依赖性的一种特殊形式之苦,即对派生类的传递依赖,这出现在基类直接地或间接地依赖于它所有的派生类时。</span><span
lang=EN-US style='font-size:12.0pt'>Visitor</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>设计模式的一些实现会导致此类依赖性。像这样的依赖性只有在类继承关系非常稳定时才是可接受的。否则,你可能希望更改设计,例如使用</span><span
lang=EN-US style='font-size:12.0pt'>Acyclic Visitor</span><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>模式</span><span lang=EN-US
style='font-size:12.0pt'>[Martin98]</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>。</span><span lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>如果仅对项目做了一些局部的修改,而增量式构建却不得不构建项目的很大一部分时,那么这就是过度相互依赖的一个症状。</span><span
lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>例外</span></b><b style='mso-bidi-font-weight:
normal'><span lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></b></p>

<p class=MsoNormal><span lang=EN-US style='font-size:12.0pt'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>只要几个类属于同一模块,一起测试,一起发布,那么它们之间的循环依赖性就不一定有害。一些模式如</span><span
lang=EN-US style='font-size:12.0pt'>Command</span><span style='font-size:12.0pt;
font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>和</span><span lang=EN-US style='font-size:12.0pt'>Visitor</span><span
style='font-size:12.0pt;font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>,在实现此类模式时如果缺乏经验,会很自然地导致接口间相互依赖。这些相互依赖性是可以打破的,但是需要明确的设计才能达到。</span><span
lang=EN-US style='font-size:12.0pt'><o:p></o:p></span></p>

</div>

</body>

</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -