Google
      
发新话题
打印

可以把重写看成是对函数的“重新赋值”

本主题由 lovechess 于 2008-6-23 08:56 移动

可以把重写看成是对函数的“重新赋值”

<><FONT color=#0000ff size=4><A href="http://blog.csdn.net/FantasiaX/archive/2008/05/22/2470849.aspx">http://blog.csdn.net/FantasiaX/archive/2008/05/22/2470849.aspx</A></FONT></P>
<><FONT color=#0000ff size=4></FONT> </P>
<><FONT color=#0000ff size=4>小序:</FONT></P>
<P>如此“不严谨”、如此“谬误”的标题,一看就是找骂的!</P>
<P><FONT color=#0000ff size=4>正文:</FONT></P>
<P>前几天在读代码的时候,发现代码里有一些函数,函数体是空的。起初是以为那是为了实现一个Interface或者是一个Abstract类而实际上又没什么实际用处才这么做的,于是没太当回事。今天Anstinus同学指导我写代码的时候,又用到这个“技术”,我才明白——这些函数体为空的函数都被声明为了virtual的,实际上“故意”留给子类去重写的(God~~哪个virtual函数不是“故意”留给子类的)。这个函数体为空的函数,在父类的某个逻辑流程中被调用了,只是因为函数体为空,而什么事都没有做。等到了子类中,一旦子类对这个函数进行了重写,就会个性化地影响到这个逻辑流程。</P>
<P>这种用法之所以特殊,是因为以前我使用virtual函数的时候,注重的是“对原有功能的改写”,这次使用virtual是对一个“根本没有功能”的函数的“功能”进行“改写”。这个感觉像什么呢?呃……以前的改写应该算做“从1到2”,而这次改写应该是“从0到1”。回到我们的标题——如果把函数看成是一个变量,函数的功能(函数体)就是它的值,而重写(override)就好像是对函数进行重新赋值一样,这样,在不同的继承级别上,函数就能获得不同的“值”。</P>
<P>在给出代码之前插一句:无论是变量名、函数名、类名……(简言之就是标识符啦),实际上都是指向一个内存地址,只是变量名指向的内存地址(再加上一个偏移量)里装的是“数值”,数据所占的内存块儿的大小由变量的类型决定;函数名指向的内存地址(再加上一个偏移量)里装的是一组CUP的指令;类名指向的内存地址里装的是这个类(无论是类还是实例)所共用的东西的清单(Table),所以,类实际上是一个作用域(Scope)。</P>
<P>OK,让我们看看今天我遇到的问题的简化版本——感谢Anstinus同学又教会我新东西</P>
<P><SPAN style="FONT-SIZE: 10pt; COLOR: blue">using</SPAN><SPAN style="FONT-SIZE: 10pt"> System;<BR><BR><SPAN style="COLOR: blue">namespace</SPAN> Sample<BR>{<BR>                <SPAN style="COLOR: blue">class</SPAN> <SPAN style="COLOR: #2b91af">AAA<BR></SPAN>                {<BR>                                <SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">void</SPAN> DoSomething()<BR>                                {<BR>                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.ForegroundColor = <SPAN style="COLOR: #2b91af">ConsoleColor</SPAN>.Yellow;<BR>                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.WriteLine(<SPAN style="COLOR: #a31515">"Do something..."</SPAN>);<BR><BR>                                                <SPAN style="COLOR: green">// Something OPTIONAL<BR></SPAN>                                                <SPAN style="COLOR: blue">this</SPAN>.DoSomethingOptional(); <SPAN style="COLOR: green">// </SPAN></SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: green">调用了,但在</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: green">AAA</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: green">类中,实际上什么事也没做</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: green"><BR><BR></SPAN><SPAN style="FONT-SIZE: 10pt">                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.ForegroundColor = <SPAN style="COLOR: #2b91af">ConsoleColor</SPAN>.Yellow;<BR>                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.WriteLine(<SPAN style="COLOR: #a31515">"Do other things..."</SPAN>);<BR>                                }<BR><BR>                                <SPAN style="COLOR: blue">protected</SPAN> <SPAN style="COLOR: blue">virtual</SPAN> <SPAN style="COLOR: blue">void</SPAN> DoSomethingOptional()                                           <SPAN style="COLOR: green">// </SPAN></SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: green">函数体是空的</SPAN><SPAN style="FONT-SIZE: 10pt; COLOR: green"><BR></SPAN><SPAN style="FONT-SIZE: 10pt">                                {<BR>                                }<BR>                }<BR><BR>                <SPAN style="COLOR: blue">class</SPAN> <SPAN style="COLOR: #2b91af">BBB</SPAN> : <SPAN style="COLOR: #2b91af">AAA<BR></SPAN>                {<BR>                                <SPAN style="COLOR: blue">protected</SPAN> <SPAN style="COLOR: blue">override</SPAN> <SPAN style="COLOR: blue">void</SPAN> DoSomethingOptional()<BR>                                {<BR>                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.ForegroundColor = <SPAN style="COLOR: #2b91af">ConsoleColor</SPAN>.Green;<BR>                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.WriteLine(<SPAN style="COLOR: #a31515">"http://blog.csdn.net/FantasiaX"</SPAN>); <BR>                                }<BR>                }<BR><BR>                <SPAN style="COLOR: blue">class</SPAN> <SPAN style="COLOR: #2b91af">CCC</SPAN> : <SPAN style="COLOR: #2b91af">AAA<BR></SPAN>                {<BR>                                <SPAN style="COLOR: blue">protected</SPAN> <SPAN style="COLOR: blue">override</SPAN> <SPAN style="COLOR: blue">void</SPAN> DoSomethingOptional()<BR>                                {<BR>                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.ForegroundColor = <SPAN style="COLOR: #2b91af">ConsoleColor</SPAN>.Magenta;<BR>                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.WriteLine(<SPAN style="COLOR: #a31515">"Some logic in CCC..."</SPAN>); <BR>                                }<BR>                }<BR><BR>                <SPAN style="COLOR: blue">class</SPAN> <SPAN style="COLOR: #2b91af">Program<BR></SPAN>                {<BR>                                <SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> Main(<SPAN style="COLOR: blue">string</SPAN>[] args)<BR>                                {<BR>                                                <SPAN style="COLOR: #2b91af">AAA</SPAN> aaa = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">AAA</SPAN>();<BR>                                                <SPAN style="COLOR: #2b91af">BBB</SPAN> bbb = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">BBB</SPAN>();<BR>                                                <SPAN style="COLOR: #2b91af">CCC</SPAN> ccc = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">CCC</SPAN>();<BR><BR>                                                aaa.DoSomething();<BR>                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.WriteLine();<BR>                                                bbb.DoSomething();<BR>                                                <SPAN style="COLOR: #2b91af">Console</SPAN>.WriteLine();<BR>                                                ccc.DoSomething();<BR>                                }<BR>                }<BR>}</SPAN><SPAN style="FONT-SIZE: 9pt"><BR></SPAN></P>
<P><SPAN style="FONT-SIZE: 9pt">===============================</SPAN></P>
<P><SPAN style="FONT-SIZE: 9pt">这是不是最佳方案?</SPAN></P>
<P><SPAN style="FONT-SIZE: 9pt">实际上,几乎任何一个逻辑我们都有不止一种办法来实现它。就拿这个例子而言,完全可以定义一个</SPAN></P>
<P><SPAN style="FONT-SIZE: 9pt"><FONT color=#0000ff size=2>delegate</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>MyDelegate</FONT><FONT size=2>();</FONT></SPAN></P>
<P><SPAN style="FONT-SIZE: 9pt">并为AAA类声明一个<FONT color=#2b91af size=2>MyDelegate</FONT>类型的field:</SPAN></P><SPAN style="FONT-SIZE: 9pt"><FONT size=2>
<P> </P>
<P> </P>
<P><SPAN style="FONT-SIZE: 9pt"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Microsoft Sans Serif','sans-serif'; mso-fareast-font-family: SimSun; mso-fareast-theme-font: minor-fareast; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-no-proof: yes">if</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Microsoft Sans Serif','sans-serif'; mso-fareast-font-family: SimSun; mso-fareast-theme-font: minor-fareast; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-no-proof: yes"> (optionalThing != <SPAN style="COLOR: blue">null</SPAN>)<BR>{<BR>        optionalThing();<BR>}</SPAN></SPAN>
<P>这样,在子类中,随便你用什么方法,只要把恰当的函数名赋值给optionalThing就可以了。这种方法比起上面代码中的方法要灵活得多、自由得多!</P>
<P>你可能会问:那为什么项目中却没有采用这种方法呢?</P>
<P>原因有如下几个——</P>
<UL>
<LI>为了使用这种方法,需要额外定义用途专一的delegate和成员变量,增加了日后维护成本
<LI>两种方法在代码量上没有太大差别
<LI>代码中的方法约束力比较强,这样,在子类中的实现看起来会比较一致,实现的时候和日后维护的时候成本较低(实际上,作为下游程序员,我也更喜欢这种方式,copy-paste就能解决很多问题) </LI></UL>
<P> 所以你看,有时候“缺点”反而是优点!</P>
<P>OK,今天就写到这儿~~做饭去喽!今天是西红柿炒鸡蛋</P></FONT></SPAN>

TOP

发新话题