我是一个C#新手,刚刚接触C#没有多长时间,学习过程中遇到好多问题,希望各位前辈给指点指点!我现在学习到OOp技术这里,多态我真的搞不明白了,请大家帮忙!
关键词:多态,c#,工作服

解决方案 »

  1.   

    三谈多态(c#描述)——善用virtual     
      (原文是Nicrosorft用ObjectPasacl写的,感觉此文不错,遂改用c#描述,希望Nicrosorft原谅没在你同意之下,便善做主张,如果您不同意,我会删掉此贴)————BeyondCsharp   
      多态性,是一种能给程序带来灵活性的东西。看过《设计模式》的程序员应该都知道,相当多的模式(几乎所有)都是依靠多态来实现的,以此给程序提供可扩展、可重用性。在《再谈多态——向上映射及VMT/DMT》一文中,提到了多态性是依赖于虚函数/虚方法(即动态绑定)来实现的,也介绍了虚函数/虚方法(virtual)的实现方法。那么本文就来谈一下,如何使用virtual、善用virtual来获取多态性给我们带来的灵活性。   
           
        实例是最好的教材,因此本文还是假设一个需求,写一个实例来讲解。不过,我想没有必要给出所有源码,因此在本文中有些实现的代码会粗略带过。另外,本文所有代码均为C#l语言编写,实现环境为VS.NET。   
           
        假设我们要编写一个纯文本内的编辑器,也就是记事本(呵呵,别嫌例子老套,记事本程序在相当多方面都是很好的教材),编辑控件我们一般会用RichTextBox,但是它们的功能都不甚强大,也许我们目前没有,但日后会找到一个更好的第三方文本编辑控件(比如,支持语法着色的)。因此,我们必须为未来的改进留下方便之门,否则到时候再重写全部程序真是太傻了。   
           
        界面层(菜单响应、状态显示等)对文本编辑器控件的控制的代码对于所有编辑器来说都是类似的,应该可以被重用。那么就必须将界面层的代码与编辑器控件的控制代码隔离开来。   
           
        如何隔离?我们可以为所有的编辑器控件指定一个公共的接口(抽象类),界面层只看得到这个接口,只使用接口提供的功能,那么,我们更换任何编辑器控件时,都不必更改界面层的代码了。   
           
        首先,抽象出编辑器的基本操作,如:Load(打开文本)、Save(保存到文件)、Copy(复制到剪贴板)等等,将这些操作作为public方法。其次,考虑这些操作中有哪些会涉及到具体相关控件的,对于这些操作,你有两种选择:1、如果完全依赖控件本身的,可以选择将其定义为虚方法或抽象虚方法(即C++中的纯虚函数);2、如果只是有部分代码依赖控件本身的,将这部分操作抽象到一个protected的抽象虚方法中,而将相同的部分代码写在基类中,并由基类的方法中调用protected的抽象虚方法。   
           
        如果还没有完全明白,请看代码:   
              //抽象类           
              public   abstract   class   Editor   
      {   
      public   Editor()   
      {   
      }   
        
                    private   string   m_FileName;   
      private   string   FileName   
      {   
      get   
      {   
      return   m_FileName;   
      }   
      set   
      {   
      m_FileName=value;   
      }   
      }   
        
      public   bool   Load(string   FileName)   
      {   
      if   (DoLoad(FileName))   
      {   
                                    m_FileName=FileName;   
      }   
      return   true;   
      }   
        
      public     bool   Save()   
      {   
      this.SaveAs(m_FileName);   
      return   true;   
      }   
                      protected   abstract   bool   DoLoad(string   FileName);   
      public   abstract   bool   SaveAs(string   FileName);   
                      //   ...   其他需要的操作,由需求而定   
        
      }   
           
        好,我们来详细说明一下Editor为什么是这个样子的。其有一个私有成员,保存编辑器所对应的文件名。然后看public部分,它至少提供了三个操作:Load——从某文件中读取文本到编辑器;Save——将文本保存到文件,文件名为m_FileName所保存的;SaveAs——以指定的一个文件名保存文本。   
        
        三个操作中,SaveAs为抽象虚方法,因为它的实际动作与每个编辑控件相关,而基类本身并不知道该如何保存文件。   
        
        Save和Load都是非虚方法,其中Save的任务很简单,就是将文本以m_FileName所保存的文件名保存,其实现可以是调用抽象的SaveAs,只需要将文件名传给SaveAs即可。基类完全可以确定如何完成Save(因为它可以保证派生类实现了SaveAs),因此其为非虚方法。   
        
        而Load呢?Load操作的步骤是:1、将文本从文件中读取到编辑器控件中;2、将m_FileName的值设置为所读取的文件名。其中第一个步骤与具体编辑器控件相关,应该是由派生类去实现它,第二个步骤派生类无法实现,因为派生类看不到私有的m_FileName成员。但即使把m_FileName移到protected节中,以使派生类可以访问它,也并非好办法,因为这样的话,在实现每个派生类时,都要记住设置m_FileName的值,这不仅造成代码重复(每个派生类都要这样做),而且这不应该是派生类的义务。因为m_FileName应该是基类的内部实现,对外不可见。因此,第二个步骤应该由基类来完成。如何达成这个目的呢?   
        
        我们可以注意到,protected节中有一个DoLoad方法,它就被用来完成第一个步骤——每个编辑器控件去将文本读入编辑器。然后,DoLoad由Load方法中被选择在适当的时机调用。   
         在该派生类中,有一个私有成员,RichTextBox控件的实例。然后覆盖(override)了基类的两个抽象虚方法:DoLoad和Save。   
        其实现如下:   
      public   class   RichTextEditor:Editor   
      {   
      public   RichTextEditor()   
      {   
      m_Editor=new   System.Windows.Forms.RichTextBox();   
      //   接着完成将TMemo实例置于界面上显示出来等操作,省略   
      }   
      private   System.Windows.Forms.RichTextBox   m_Editor;   
        
      protected   override   bool   DoLoad(string   FileName)   
      {   
              m_Editor.LoadFile(FileName);   
      return   true;   
      }   
        
      public   override   bool   SaveAs(string   FileName)   
      {   
      m_Editor.SaveFile(FileName);   
      return   true;   
      }   
        //   ...其它需要的操作   
      }     
         很好,这样的实现已经可以使个部分运作正常了。如果,今后找到更好的编辑器控件,只需要从Editor派生,再实现一个XXXEditor类即可,其他部分的代码不用作任何改动。而且,具体实现的TXXXEditor类中的代码,只和具体控件本身特性相关(如:读取、保存文件的方法),而公共逻辑也已经在Editor类中实现了。   
           
        virtual的使用方法,基于笔者个人认识与经验:   
           
        1、如果基类不知道如何实现某方法(只有派生类知道),而基类的其他方法又必须使用该方法,则把该方法声明为抽象虚方法——   virtual;   abstract;(即C++的纯虚函数)。   
           
        2、如果基类能够为某方法提供一种默认实现,但派生类可能完全重写这个实现,则将该方法声明为虚方法——   virtual;并实现默认算法。   
        
        3、如果基类能够且必须提供某方法的部分的实现,而派生类必须提供另一部份的实现,则将该方法声明为非虚方法,并在基类中为其配套提供一个虚方法或抽象虚方法,以允许由基类本身调用和被派生类覆盖。犹如上例中的Load与DoLoad。   
           
        善用virtual,善用多态,你的代码将更具灵活性!   
    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yumanqing/archive/2007/03/01/1518233.aspx
    参考:http://www.cnblogs.com/Bear-Study-Hard/archive/2006/09/06/496366.html
      

  2.   

    1楼说的很形象。多态简单点也就是一个Action对应有多个对象的实现.
      

  3.   

    上个简单的代码class Polymorphism
        {
            public static void Main()
            {
                Ianimal dog = new Dog();
                dog.叫();
                Ianimal cat = new Cat();
                cat.叫();
                Ianimal cabrite = new Cabrite();
                cabrite.叫();
                Console.ReadKey();
            }
        }    public interface Ianimal
        {
            void 叫();
        }    public class Dog : Ianimal
        {
            public void 叫()
            {
                Console.WriteLine("狗在叫");
            }
        }    public class Cat : Ianimal
        {
            public void 叫()
            {
                Console.WriteLine("猫在叫");
            }
        }    public class Cabrite : Ianimal
        {
            public void 叫()
            {
                Console.WriteLine("蜥蜴不会叫");
            }
        }申明都是Ianimal接口,但是由于实例不同,调用的方法也不一样。
      

  4.   


    再把Main()函数改改public static void Main()
            {
                List<Ianimal> animalList = new List<Ianimal>();
                animalList.Add(new Dog());
                animalList.Add(new Cat());
                animalList.Add(new Cabrite());
                foreach (Ianimal animal in animalList)
                {
                    animal.叫();
                }            Console.ReadKey();
            }
      

  5.   

    都是图形,但各有分别
    using System ; public class DrawingBase { public virtual void Draw( ) { Console.WriteLine("a generic drawing object.") ; 


    public class Line : DrawingBase 

    public override void Draw( ) 
    { Console.WriteLine("a Line.") ; } 

    public class Circle : DrawingBase 

    public override void Draw( ) { Console.WriteLine("a Circle.") ; } 

    public class Square : DrawingBase 

    public override void Draw( ) 
    { Console.WriteLine("a Square.") ; } 
    } public class DrawDemo 

    public static int Main(string[] args) 

    DrawingBase [] dObj = new DrawingBase [4]; 
    dObj[0] = new Line( ) ; 
    dObj[1] = new Circle( ) ; 
    dObj[2] = new Square( ) ; 
    dObj[3] = new DrawingBase( ) ; 
    foreach (DrawingBase drawObj in dObj) 
    drawObj.Draw( ) ; 
    return 0; } }
      

  6.   

    多个子类比如B、C、D,都继承自己A,那B、C、D与A之间的关系就是多态了。