c++中的虚函数

http://www.cnblogs.com/wangxiang/archive/2009/01/08/1079548.html

 

<script type="text/javascript"> //<![CDATA[ var theForm = document.forms['Form1']; if (!theForm) { theForm = document.Form1; } function __doPostBack(eventTarget, eventArgument) { if (!theForm.onsubmit || (theForm.onsubmit() != false)) { theForm.__EVENTTARGET.value = eventTarget; theForm.__EVENTARGUMENT.value = eventArgument; theForm.submit(); } } //]]> </script> <script type="text/javascript"> var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); </script> <script type="text/javascript"> try { var pageTracker = _gat._getTracker("UA-12540159-1"); pageTracker._trackPageview(); } catch(err) {}</script>

关于虚函数一个很好的解释

虚函数 ( virtual )

一、 OOP 的目标:

使用面向对象的开发过程就是在不断地抽象事物的过程,我们的目标就是抽象出一个高内聚、低偶合,易于维护和扩展的模型。

 

二、遇到的问题:

但 是在抽象过程中我们会发现很多事物的特征不清楚,或者很容易发生变动,怎么办呢?比如飞禽都有飞这个动作,但是对于不同的鸟类它的飞的动作方式是不同的, 有的是滑行,有的要颤抖翅膀,虽然都是飞的行为,但具体实现却是千差万别,在我们抽象的模型中不可能把一个个飞的动作都考虑到,那么怎样为以后留下好的扩 展,怎样来处理各个具体飞禽类千差万别的飞行动作呢?比如我现在又要实现一个类“鹤”,它也有飞禽的特征(比如飞这个行为),如何使我可以只用简单地继承 “飞禽”,而不去修改“飞禽”这个抽象模型现有的代码,从而达到方便地扩展系统呢?

 

三、解决上述问题的方法:

面向对象的概念中引入了虚函数来解决这类问题。

使用虚函数就是在父类中把子类中共有的但却易于变化或者不清楚的特征抽取出来,作为子类需要去重新实现的操作( override ),我们可以称之做“热点”。而虚拟函数也是 OOP 中实现多态的关键之一。

还是上面的例子( C# ):

 

class 飞禽

        public string wing;             // 翅膀

        public string feather;          // 羽毛  

        ……                             // 其它属性和行为  

        public virtual bool Fly()       // 利用关键字 virtual 来定义为虚拟函数,这是一个热点

        {

                // 空下来让子类去实现

        }

}

 

class 麻雀 : 飞禽                       // 麻雀从飞禽继承而来

{

        ……     // 定义麻雀自己特有的属性和行为

        public override bool Fly()      // 利用关键字 override 重载飞翔动作 ,实现自己的飞翔

        {

                ……     // 实现麻雀飞的动作

        }

}

 

class  鹤 : 飞禽                        // 鹤从飞禽继承而来

{

         ……     // 定义鹤自己的特有的属性和行为

        public override bool Fly()      // 利用关键字 override 重载实现鹤的飞翔

        {

                ……     // 实现鹤飞的动作

        }

}

 

这样我们只需要在抽象模型“飞禽”里定义 Fly() 这个行为,表示所有由此“飞禽”派生出去的子类都会有 Fly() 这个行为,而至于 Fly() 到底具体是怎么实现的,那么就由具体的子类去实现就好了,不会再影响“飞禽”这个抽象模型了。

 

比如现在我们要做一个飞禽射击训练的系统,我们就可以这样来使用上面定义的类:

// 如何来使用虚拟函数,这里同时也是一个多态的例子.

// 定义一个射击飞禽的方法

// 注意这里申明传入一个“飞禽”类作为参数,而不是某个具体的“鸟类”。好处就是以后不管再出现多少

// 种鸟类,只要是从飞禽继承下来的,都照打不误:)(多态的方式)

void ShootBird(飞禽 bird) 

{

        // 当鸟在飞就开始射击

        if (bird.Fly())

        {

                ……     // 射击动作

        }

}

 

static void main()

{

        / /打麻雀

        ShootBird( new 麻雀());

        // 打鹤

        ShootBird( new 鹤());    

        // 都是打鸟的过程,我只要实现了具体某个鸟类(从“飞禽”派生而来)的定义,就可以对它

        // 进行射击,而不用去修改ShootBird函数和飞禽基类

        ShootBird( new 其它的飞禽());      

}

 

 

四、 C# 种虚拟函数的的执行过程:

C++ Java 等众多 OOP 语言里都可以看到 virtual 的身影,而 C# 作为一个完全面向对象的语言当然也不例外。

虚拟函数从 C# 的 程序编译的角度来看,它和其它一般的函数有什么区别呢?一般函数在编译时就静态地编译到了执行文件中,其相对地址在程序运行期间是不发生变化的,也就是写 死了的!而虚函数在编译期间是不被静态编译的,它的相对地址是不确定的,它会根据运行时期对象实例来动态判断要调用的函数,其中那个申明时定义的类叫申明 类,那个执行时实例化的类叫实例类。

         如: 飞禽 bird = new 麻雀();

那么飞禽就是 申明类, 麻雀是 实例类。       

具体的检查的流程如下:

  1 当调用一个对象的函数时,系统会直接去检查这个对象申明定义的类,即申明类,看所调用的函数是否为虚函数;

  2 如果不是虚函数,那么它就直接执行该函数。而如果有 virtual 关键字,也就是一个虚函数,那么这个时候它就不会立刻执行该函数了,而是转去检查对象的实例类。

  3 在这个实例类里,他会检查这个实例类的定义中是否有重新实现该虚函数(通过 override 关键字),如果是有,那么 OK ,它就不会再找了,而马上执行该实例类中的这个重新实现的函数。而如果没有的话,系统就会不停地往上找实例类的父类,并对父类重复刚才在实例类里的检查,直到找到第一个重载了该虚函数的父类为止,然后执行该父类里重载后的函数。

 

知道这点,就可以理解下面代码的运行结果了:

class A

{

        protected virtual Func()        // 注意virtual,表明这是一个虚拟函数

        {

                Console.WriteLine("Func In A");

        }

}

 

class B : A                             // 注意B是从A类继承,所以A是父类,B是子类

{

        protected override Func()       // 注意override ,表明重新实现了虚函数

        {

                Console.WriteLine("Func In B");

        }

}

 

class C : B                             // 注意C是从A类继承,所以B是父类,C是子类

{

       

}

 

class D : A                             // 注意B是从A类继承,所以A是父类,D是子类

{

        protected new Func()            // 注意new ,表明覆盖父类里的同名类,而不是重新实现

        {

                Console.WriteLine("Func In B");

        }

}

 

static void main()

{

        A a;                            // 定义一个a这个A类的对象.这个A就是a的申明类

        A b;                            // 定义一个b这个A类的对象.这个A就是b的申明类

        A c;                            // 定义一个c这个A类的对象.这个A就是b的申明类

        A d;                            // 定义一个d这个A类的对象.这个A就是b的申明类

        a = new A();                    // 实例化a对象,A是a的实例类

        b = new B();                    // 实例化b对象,B是b的实例类

        c = new C();                    // 实例化b对象,C是b的实例类

        d = new D();                    // 实例化b对象,D是b的实例类

        a.Func() ;       

        // 执行a.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类A,就为本身 4.执行实例类A中的方法 5.输出结果 Func In A      

        b.Func() ;    

        // 执行b.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类B,有重载的 4.执行实例类B中的方法 5.输出结果 Func In B

        c.Func() ;    

        // 执行c.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类C,无重载的 4.转去检查类C的父类B,有重载的 5.执行父类B中的Func方法 5.输出结果 Func In B

        d.Func();

        // 执行d.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类D,无重载的(这个地方要注意了,虽然D里有实现Func(),但没有使用override关键字,所以不会被认为是重载) 4.转去检查类D的父类A,就为本身 5.执行父类A中的Func方法 5.输出结果 Func In A

        D d1 = new D()

        d1.Func();      // 执行D类里的Func(),输出结果 Func In D }

 

 

0
0
(请您对文章做出评价)
« 上一篇: DataRow对象数据绑定问题
» 下一篇: javascripter之配合dot net工程师。
<script type="text/javascript"> try { GS_googleAddAdSenseService("ca-pub-4210569241504288"); GS_googleEnableAllServices(); } catch (e) { } </script> <script type="text/javascript"> try { GA_googleAddSlot("ca-pub-4210569241504288", "cnblogs_blogpost_body"); GA_googleAddSlot("ca-pub-4210569241504288", "cnblogs_commentbox_up"); GA_googleAddSlot("ca-pub-4210569241504288", "cnblogs_blogpost_bottom"); GA_googleAddSlot("ca-pub-4210569241504288", "cnblogs_blogpost_bottom1"); } catch (e) { } </script> <script type="text/javascript"> try { GA_googleFetchAds(); } catch (e) { } </script> <script type="text/javascript"> var blog_ad_has_shown = false; </script>
posted @ 2008-02-24 17:07 王祥 @ dot net 驿站 阅读(733) 评论(1)   编辑 收藏 所属分类: 开源(asp.net系统)

   回复    引用     
#1楼 2009-01-08 08:46 | Eson[未注册用户]
不错 诠释的很形象,表达的意思很明确
<script type="text/javascript"> var commentAuthorHasChecked = false; var commentAuthorIsValid = false; var commentUrlIsValid = true; var commentEmailIsValid = true; var authenCodeHasChecked = false; var authenCodeIsValid = true; var hasLogined = false; function PostComment() { var isValid = true; if($("#wrapAuthenCode").css("display")=="none"){ ShowAuthenCode(); $("#tip_AuthenCode").css("color","red"); $("#tip_AuthenCode").html("请输入验证码!"); isValid = false; } if(!hasLogined && !commentAuthorHasChecked){ CheckAuthor(); } if(!hasLogined && !commentAuthorIsValid){ isValid = false; } if(!authenCodeHasChecked){ CheckAuthenCode(); } if(!authenCodeIsValid){ isValid = false; } if(!hasLogined && !commentUrlIsValid){ isValid = false; } if(!commentEmailIsValid){ isValid = false; } if(!CheckCommentContent()){ isValid = false; } if(!isValid){ return; } var content = $("#tbCommentBody").val(); if(content.length>2000){ alert("评论内容过长!不允许发布!"); return; } if(content.indexOf(" E         E          E      ")>=0){ alert("该内容不允许布!"); return; } if ($("#span_comment_posted").html()!='' && $("#span_comment_posted").html()==content){ alert("该评论已发表过!"); return; } $("#tip_comment").html("评论提交中..."); $("#span_comment_posted").html(content); //content = content.replace("'", "//'"); var email = $("#tbCommentEmail").val(); var authenNum = $("#tbAuthenCode").val(); var authenId = $("#span_comment_test").html(); var comment = {}; comment.authenNum = authenNum; comment.authenId= authenId; comment.parentId = 0; comment.blogId = 0; comment.sourceUrl = ''; comment.author = $("#tbCommentAuthor").val(); comment.url = $("#tbCommentAuthorUrl").val(); comment.authenCode = $("#tbAuthenCode").val(); comment.email = email; comment.title = ''; comment.content = content; comment.parentCommentId = $("#span_parentcomment_id").html(); $.ajax({ url: '/ws/CommentService.asmx/AddAnonymousComment', data: $.toJSON(comment), type: "post", dataType: "json", contentType: "application/json; charset=utf8", success: function(data) { if (data.d["IsSuccess"]) { ShowCommentMsg("感谢您的回复:)"); //RereshComments2(comment.parentId); $("#tbCommentBody").val(''); //$("#divCommentShow").html(data.d["ReturnData"]+content.replace(//n/g,"<br/>")+"<br/><br/>"); $("#divCommentShow").html($("#divCommentShow").html()+data.d["ReturnData"]); $("#tip_AuthenCode").html(''); RefreshAuthenCode(); $("#tbAuthenCode").val(""); CommentNotify(data.d["CommentID"]); } else { ShowCommentMsg(data.d["ReturnData"]);//"抱歉!评论提交失败!请与管理员联系。"); $("#span_comment_posted").html(''); } }, error: function(xhr) { ShowCommentMsg("抱歉!评论提交失败!请与管理员联系。"); $("#span_comment_posted").html(''); //alert(xhr.responseText); } } ); } function RefreshAuthenCode(){ AjaxPost("/ws/CommentService.asmx/RefreshAuthenCode","{}",RefreshImg); $("#lnkRereshAuthenCode").html("<span style='color:red'>刷新中...</span>"); return false; } function RefreshImg(response){ $("#imgAuthenCode").attr("src","/Modules/CaptchaImage/ValidCodeImage.aspx?id="+encodeURIComponent(response)); $("#span_comment_test").html(response); $("#lnkRereshAuthenCode").html("看不清,换一个"); } function ShowAuthenCode(){ //if($("#wrapAuthenCode").css("display")=="none"){ // AjaxPost("/ws/CommentService.asmx/RefreshAuthenCode","{}",ShowAuthenCodeOk); //} $("#wrapAuthenCode").show(); } function ShowAuthenCodeOk(response){ UpdateAuthenCode(); $("#tbAuthenCode").val(""); $("#wrapAuthenCode").show(); $("#tip_AuthenCode").html(''); } function CheckAuthor(isOnblur){ commentAuthorHasChecked = true; var maxLength = 30; if($("#tbCommentAuthor").val().length == 0){ $("#tip_author").html("请输入您的昵称!"); commentAuthorIsValid = false; return false; } else if($("#tbCommentAuthor").val().length > maxLength){ $("#tip_author").html("昵称不允许超过" + maxLength + "个字符!"); commentAuthorIsValid = false; return false; } else{ //if(isOnblur){ AjaxPost("/ws/CommentService.asmx/IsAuthorExist","{author:'"+$("#tbCommentAuthor").val()+"'}" ,OnCheckAuthorExist); //} //else{ // $("#tip_author").html(""); // commentAuthorIsValid = true; //} return true; } } function OnCheckAuthorExist(response){ if(!response){ $("#tip_author").html(""); commentAuthorIsValid = true; } else{ $("#tip_author").html("该昵称已被使用,请更换昵称"); commentAuthorIsValid = false; } } function CheckUrl(){ var maxLength = 50; var url = $("#tbCommentAuthorUrl").val(); if(url.length == 0){ commentUrlIsValid = true; return true; } else if(url.length > maxLength){ $("#tip_url").html("主页地址不允许超过" + maxLength + "个字符!"); commentUrlIsValid = false; return false; } else if(url.indexOf("http://")!=0 || url.indexOf(".") < 0){ $("#tip_url").html("主页地址要以“http://”开头"); commentUrlIsValid = false; return false; } else{ $("#tip_url").html(""); commentUrlIsValid = true; return true; } } function CheckEmail(){ var email = $("#tbCommentEmail").val(); if(email.length>0){ var regExp = new RegExp("//w+@((//w|/-)+//.)+[a-z]{2,3}"); if(!regExp.test(email)){ $("#tip_email").html("请输入正确的邮件地址!"); commentEmailIsValid = false; } else{ commentEmailIsValid = true; $("#tip_email").html(""); } } else{ commentEmailIsValid = true; $("#tip_email").html(""); } } function CheckAuthenCode(){ authenCodeHasChecked = true; var num = $("#tbAuthenCode").val(); var id = $("#span_comment_test").html(); $("#tip_AuthenCode").css("color","red"); if(num.length==0){ authenCodeIsValid = false; $("#tip_AuthenCode").html("请输入验证码!"); return; } else if(num.length!=4){ authenCodeIsValid = false; $("#tip_AuthenCode").html("请输入四位数字!"); return; } else if(new RegExp("(/d+)").test(num)){ authenCodeIsValid = false; $("#tip_AuthenCode").html("请输入四位数字!"); return; } else{ AjaxPost("/ws/CommentService.asmx/CheckAuthenCode","{number:"+num+",id:'"+id+"'}", OnCheckAuthenCode); } } function OnCheckAuthenCode(response){ if(response){ $("#tip_AuthenCode").css("color","green"); $("#tip_AuthenCode").html("验证码输入正确!"); authenCodeIsValid = true; } else{ $("#tip_AuthenCode").css("color","red"); $("#tip_AuthenCode").html("验证码输错啦!"); RefreshAuthenCode(); authenCodeIsValid = false; } } function CheckCommentContent(){ if($("#tbCommentBody").val().length==0){ alert("请输入评论内容!"); return false; } return true; } </script>

<script type="text/javascript"> try { SyntaxHighlighter.config.clipboardSwf = 'http://common.cnblogs.com/flash/clipboard.swf'; SyntaxHighlighter.all(); } catch (e) { } </script> <script type="text/javascript"> var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); </script> <script type="text/javascript"> try { var pageTracker = _gat._getTracker("UA-476124-1"); pageTracker._trackPageview(); } catch (err) { }</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值