100165817.htm
来自「C#高级编程(第三版),顶死你们。。 。up」· HTM 代码 · 共 292 行 · 第 1/5 页
HTM
292 行
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> // some groovy implementation</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> return 0;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">}</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">一年后,基类的编写者决定扩展基类的功能。为了保持一致,他也添加了一个名为</span><span lang="EN-US">MyGroovyMethod()</span><span style="FONT-FAMILY: 宋体">的方法,该方法的名称和签名与前面添加的方法的名称和签名相同,但并不完成相同的工作。在使用基类的新方法编译代码时,在应该调用哪个方法上就会有潜在的冲突。这在</span><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">中完全合法,但因为我们的</span><span lang="EN-US">MyGroovyMethod()</span><span style="FONT-FAMILY: 宋体">与基类的</span><span lang="EN-US">MyGroovyMethod()</span><span style="FONT-FAMILY: 宋体">不相关,运行这段代码的结果就可能不是我们希望的结果。</span><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">已经为此设计了一种方式,可以很好地处理这种情况。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体; LETTER-SPACING: -0.1pt">首先,系统会发出警告。在</span><span lang="EN-US" style="LETTER-SPACING: -0.1pt">C#</span><span style="FONT-FAMILY: 宋体; LETTER-SPACING: -0.1pt">中,应使用</span><span lang="EN-US" style="LETTER-SPACING: -0.1pt">new</span><span style="FONT-FAMILY: 宋体; LETTER-SPACING: -0.1pt">关键字声明我们要隐藏一个方法,如下所示:</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span><span lang="EN-US">class MyDerivedClass : HisBaseClass</span></span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> public new</span><span lang="EN-US"> int MyGroovyMethod()</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> // some groovy implementation</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> return 0;</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">}</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">但是,我们的</span><span lang="EN-US">MyGroovyMethod()</span><span style="FONT-FAMILY: 宋体">没有声明为</span><span lang="EN-US">new</span><span style="FONT-FAMILY: 宋体">,所以编译器会认为它隐藏了基类的方法,但没有显式声明,因此发出一个警告</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">这也适用于把</span><span lang="EN-US">MyGroovyMethod()</span><span style="FONT-FAMILY: 宋体">声明为</span><span lang="EN-US"> virtual)</span><span style="FONT-FAMILY: 宋体">。如果愿意,可以给我们的方法重命名,以响应该警告。这么做,是最好的情形,因为这会避免许多冲突。但是,如果觉得重命名方法是不可能的</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">例如,已经为其他公司把软件发布为一个库,所以无法修改方法的名称</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">,则所有的已有客户机代码仍能正确运行,选择我们的</span><span lang="EN-US">MyGroovyMethod()</span><span style="FONT-FAMILY: 宋体">。这是因为访问这个方法的已有代码必须通过对</span><span lang="EN-US">MyDerivedClass(</span><span style="FONT-FAMILY: 宋体">或进一步派生的类</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">的引用进行选择。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">已有的代码不能通过对</span><span lang="EN-US">HisBaseClass</span><span style="FONT-FAMILY: 宋体">的引用访问这个方法,因为在对</span><span lang="EN-US">HisBaseClass</span><span style="FONT-FAMILY: 宋体">的早期版本进行编译时,会产生一个编译错误。这个问题只会发生在将来编写的客户机代码上。</span><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">会发出一个警告,告诉用户在将来的代码中可能会出问题——用户应注意这个警告,不要试图在将来的代码中通过对</span><span lang="EN-US">HisBaseClass</span><span style="FONT-FAMILY: 宋体">的引用调用</span><span lang="EN-US">MyGroovyMethod()</span><span style="FONT-FAMILY: 宋体">方法,但所有已有的代码仍会正常工作。这是比较微妙的,但很好地说明了</span><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">如何处理类的不同版本。</span></p>
<h3 style="MARGIN: 8.15pt 0cm"><span lang="EN-US">4.2.3 </span><span style="FONT-FAMILY: 黑体">调用函数的基础版本</span></h3>
<p class="MsoNormal"><span><span lang="EN-US">C#</span></span><span style="FONT-FAMILY: 宋体">有一种特殊的语法用于从派生类中调用方法的基础版本:</span><span lang="EN-US">base.<MethodName>()</span><span style="FONT-FAMILY: 宋体">。例如,假定派生类中的一个方法要返回基类的方法返回的值的</span><span lang="EN-US">90%</span><span style="FONT-FAMILY: 宋体">,就可以使用下面的语法:</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">class CustomerAccount</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">{</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> public virtual decimal CalculatePrice()</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> // implementation</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> return 0.0M;</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">} <span></span></span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">class GoldAccount : CustomerAccount</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> public override decimal CalculatePrice()</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> return base.CalculatePrice() * 0.9M;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">} </span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">这个语法类似于</span><span lang="EN-US">Java</span><span style="FONT-FAMILY: 宋体">,但</span><span lang="EN-US">Java</span><span style="FONT-FAMILY: 宋体">使用关键字</span><span lang="EN-US">super</span><span style="FONT-FAMILY: 宋体">而不是</span><span lang="EN-US">base</span><span style="FONT-FAMILY: 宋体">。</span><span lang="EN-US">C++</span><span style="FONT-FAMILY: 宋体">没有类似的关键字,但需要对类名进行显式说明</span><span lang="EN-US">(CustomerAccount : CalculatePrice())</span><span style="FONT-FAMILY: 宋体">。</span><span lang="EN-US">C++</span><span style="FONT-FAMILY: 宋体">中对应于</span><span lang="EN-US">base</span><span style="FONT-FAMILY: 宋体">的内容都比较模糊,因此</span><span lang="EN-US">C++</span><span style="FONT-FAMILY: 宋体">允许多重继承。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">注意,可以使用</span><span lang="EN-US">base.<MethodName>()</span><span style="FONT-FAMILY: 宋体">语法调用基类中的任何方法,不必是在同一个方法的重载中调用它。</span></p>
<h3 style="MARGIN: 8.15pt 0cm"><span lang="EN-US">4.2.4 </span><span style="FONT-FAMILY: 黑体">抽象类和抽象函数</span></h3>
<p class="MsoNormal"><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">允许把类和函数声明为</span><span lang="EN-US">abstract</span><span style="FONT-FAMILY: 宋体">,抽象类不能实例化,而抽象函数没有执行代码,必须在非抽象的派生类中重写。显然,抽象函数也是虚拟的</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">但也不需要提供</span><span lang="EN-US">virtual</span><span style="FONT-FAMILY: 宋体">关键字,实际上,如果提供了该关键字,就会产生一个语法错误</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">。如果类包含抽象函数,该类将也是抽象的,也必须声明为抽象的:</span></p>
<p class="2" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">abstract class Building</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> public abstract decimal CalculateHeatingCost(); // abstract method</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">}</span></p>
<p class="MsoNormal"><span lang="EN-US">C++</span><span style="FONT-FAMILY: 宋体">开发人员要注意</span><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">中的一些语法区别。</span><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">不支持采用</span><span lang="EN-US">=0</span><span style="FONT-FAMILY: 宋体">语法来声明抽象函数。在</span><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">中,这个语法有误导作用,因为可以在类声明的成员字段上使用</span><span lang="EN-US">=<value></span><span style="FONT-FAMILY: 宋体">,提供初始值:</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">abstract class Building</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> private bool damaged = false; // field</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> public abstract decimal CalculateHeatingCost(); // abstract method</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">}</span></p>
<p class="a3" style="MARGIN-TOP: 8.15pt; TEXT-INDENT: 21.45pt"><span style="FONT-FAMILY: 黑体">注意:</span></p>
<p class="a1" style="MARGIN-BOTTOM: 8.15pt; TEXT-INDENT: 21.45pt"><span lang="EN-US">C++</span><span style="FONT-FAMILY: 楷体_GB2312">开发人员还要注意术语上的细微差别:在</span><span lang="EN-US">C++</span><span style="FONT-FAMILY: 楷体_GB2312">中,抽象函数常常声明为纯虚函数,而在</span><span lang="EN-US">C#</span><span style="FONT-FAMILY: 楷体_GB2312">中,仅使用抽象这个术语。</span></p>
<h3 style="MARGIN: 8.15pt 0cm"><span lang="EN-US">4.2.5 </span><span style="FONT-FAMILY: 黑体">密封类和密封方法</span></h3>
<p class="MsoNormal"><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">允许把类和方法声明为</span><span lang="EN-US">sealed</span><span style="FONT-FAMILY: 宋体">,对于类来说,这表示不能继承该类,对于方法来说;这表示不能重写该方法。</span></p>
<p class="2" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">sealed class FinalClass</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> // etc</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">}</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">class DerivedClass : FinalClass // wrong. Will give compilation error </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> // etc</span></p>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?