如题目所说:在基类中定义的虚方法,在派生类中即然可以重写,也可以不重写,而且派生类中可以随时扩展方法,所以我让为虚(virtual)太多余了。请前辈,给我说说,我想的对不。在线,明白了立即给分。

解决方案 »

  1.   

    一个类中的方法定义为virtual,才能在它的派生类中重写该方法
      

  2.   

    @ustbwuy谢您回贴。但是,打个比方
    clash one 
    {
    public one()
    {
    }
    public virtual void method()
    {
    Console.Write(" method");
    }
    }
    class two:one
    {
    public override void method()
    {
    Console.Write("override method");
    }
    }如果我在one 类中没有用public virtual void method(),而是在two类中直接产生
    public void method()
    {}效果,不是一样的吗?也就是我,说的,virtual是多余的,因为派生只要愿意,随时都可以,生明一个方法。
      

  3.   

    是的 可以重写也可不重写  用virtual只是告诉你这个类或者这个方法可以任你扩展
      

  4.   

    也就是说,Virtual有存在的必要性吗?或者说,它的存在,有没有不可替代的一面??请高手指一下。
      

  5.   

    如果你那样说的话 干嘛还要继承one类咧
      

  6.   

    to wen01071081
    是的 可以重写也可不重写  用virtual只是告诉你这个类或者这个方法可以任你扩展
    =============================================================================您上面的话“可以任你扩展”,我承认是对的,但是派生类可以随时扩展基类,那么要virtual还有什么意义??
      

  7.   

    @wen01071081
    如果one中有必须实现的方法,那么必须要继承它喽,可是Virtual的存在就是不那么可推敲了。有它,和没有它,派生类都不受影响,您能给指一个virtual真正有用的例子吗??或是说明它的真正发明用处。
      

  8.   

    基类写virtual的意思就是告诉派生类,你如果有兴趣,最好能把我override了,但是,如果你没有override我也没有关系,毕竟基类这个virtual方法派生类也可以将就用用
      

  9.   

    //效果,不是一样的吗?
    效果不一样!
    只有virtual方法可以override
    没有override关键字相当于省略了new关键字,实际是隐藏而不是重写了
    隐藏的话,就没有多态性
    楼主应该知道多态性是OO的基本特征之一
      

  10.   

    我自己分析,既然virtual都是在基类中出现,那派生类就都有virtual的影子(如果派生类想让它实现的话)。可是,virtual又不象override一样,可以用于多态(因为,派生类有的实现了virtual,有的没有,就不能用多态的方法操作它们)。真是不解,它的用处有何特别
      

  11.   

    //只有virtual方法可以override
    不好意思,这个说得有点片面
    只有virtual、abstract或override方法可以override
      

  12.   

    @viena() 维也纳() 您是从用法上说的,我同意您说的。但是,我想听,它为什么存在,现在我的结论是,没有virtual方法,派生类,依然可以实现任何方法。
      

  13.   

    对派生类的使用,我们往往会把派生的类看作它的某一个父类来处理。
    如果只是在子类里加了一个方法,那么当做某个父类处理的时候,在父类里就找不到方法了。
    使用Virtual声明成员就保证了这一点,不但父类有处理,子类也可以有处理,使得面向对象的能够很好的被实现了。
      

  14.   

    to hbxtlhx(平民百姓-自已动手,丰衣足食)您还是给我讲的继承关系,或是我没有明白您话的意思。
      

  15.   

    给你讲个故事:
    踢球A要求:我踢进门就可以
    B要求:我一定要用内脚背踢进去
    C要求:我一定要用外脚背如果教练没有说明怎么使用内外脚背的踢法,只是教了普通踢法,那么
    A就不用自己想办法怎么踢了,只要用教练教的就行
    BC就不样了,内外脚背有特殊的技术嘀,所以要自己想办法了
      

  16.   

    主要是不明白什么时候必须用Virtual?
      

  17.   

    //现在我的结论是,没有virtual方法,派生类,依然可以实现任何方法
    没有virtual或abstract,就没有override!就没有多态性!明白?
      

  18.   

    多写几个程序就明白了Virtual是多么有用的了
      

  19.   

    您上面的话“可以任你扩展”,我承认是对的,但是派生类可以随时扩展基类,那么要virtual还有什么意义??
    ==================
    1。
    LZ 这里, 你的思路取道错了,应该这样理解,只有加了 virtual 修饰符的才可以被子类重载,
    否则,不可以。即,virtual 告诉编译器,我要实现多态的功能,如果不加,编译器认为你要定义一个心的方法,覆盖基类方法,csc 会给你一个警告,要你显示使用 new 修饰符
    2。程序语言设计里面有两种东东,语法与语义,知道不?编译器即根据语言的设计者定义的 语法与语义 规则, 来翻译你的代码,翻译/解释成机器语言就比如说,我们中文习惯顺序, 英语喜欢倒序,一样virtual/override 这是 C# 实现多态重载的规则,假如方法、属性没有这个修饰符,根据预定义规范,编译器不当你正确的重载方式,甚至无法编译通过。3。
    你问它有没有存在的必要?没有人能给你答案,关键字 virtual 是 C# 延续 C++ 的风格, Java 是 C++/C# 的近亲,它就没有整个关键字,在 Java 中,任何方法都可以被子类重载,
    但,
    C#, 你必须加上 virtual 才可以被子类重载,否则,我不实现 多态 功能4。
    你问没有 virtual 是否可以达到同样的功能?可以啊,人家 Java 不就实现了,可是假如你深入的了解,就会发现,他们的实现方式还是有区别的,
    那么,我们作为语言的消费者,使用上肯定也有区别,
    到底什么区别, 自己你实践才能体会,
      

  20.   

    @viena() 维也纳() 我认为,abstract对于多态性是必要的,是不可缺少的。可是virtual,我让认为,它对于多态性是没有用的。如果我哪说错了,请您指正。
      

  21.   

    abstract实际上是是隐式的virtual,
    也就是说,override的方法归根到底基类必须是虚方法!
    但virtual方法未必是abstract的
    abstract的方法只能在abstract类中出现
    而实际上有大量非抽象类,难道就不能实现多态?
      

  22.   

    建议楼主多看看接口,然后理解下多态,最后在看下故事,你会发现一个函数可以用Virtual来实现不同的用处。每个实现都有不同特殊点。但总体来说他们都有一个基本。故事:A要求:我踢进门就可以
    B要求:我一定要用内脚背踢进去
    C要求:我一定要用外脚背如果教练没有说明怎么使用内外脚背的踢法,只是教了普通踢法,那么
    A就不用自己想办法怎么踢了,只要用教练教的就行
    BC就不样了,内外脚背有特殊的技术嘀,所以要自己想办法了
      

  23.   

    @viena() 维也纳不好意思,麻烦您,给简单又简单地,写一小小段代码,来说明您说的好吗
      

  24.   

    嘘嘘嘘嘘嘘嘘嘘嘘嘘嘘嘘嘘嘘嘘嘘嘘嘘嘘!!!!!!!!!!!!
    语言如果没有 virtual/abstract/override 是不是可以实现多态??答案是肯定的!!!!!!!!!!!!!!!!!!!!!!!!!C# 有 virtual/abstract/overrideC++ 只有 virtualJava 只有 abstract
    他们不都实现了 多态 嘛???????
    LZ 你完全可以设计一种语言,
    不用上面三个的任何关键字,
    完全也可以实现多态功能, 
    但是你得有足够的功底,足够的数学功底Understand??????????????????????????????
      

  25.   

    为什么存在virtual的道理其实很简单,它体现了继承和多态重要特征好比VS2003时的CS都有这个东东 override   protected   void   OnInit(EventArgs   e)   
      {   
       InitializeComponent();   
      base.OnInit(e);   
      }   
      

  26.   

    @Jinglecat(晓风残月 >> 问题需简洁,错误要详细)您一定是高手,可是您没有看到我的题目吗??“刚学C#”,更准确的说“刚学OO(p)”,初学,遇到不懂的,就不应该问问???这年头,没有钱受歧视,没有想到,初学也受歧视,还让不让人活了???
      

  27.   

    Lz,别急啊我说说
    多态性,编译时的多态性是通过重载(overload)来实现,运行时的多态性是通覆写(override)虚成员实现
    而虚拟方法和覆写(override)是实现运行时的多态性我收藏了一篇文章,您看看,应该会有所帮助。学习是一点一点的,不要急我先找找。
      

  28.   

    其实仔细看,你会发现Jinglecat先生的最上面的解答很权威,想必没有任何歧视谁的意思
      

  29.   

    找到了,地址如下:
    http://blog.csdn.net/love610/archive/2006/02/06/593203.aspx例子比较简单,易懂很。日后,代码写多了,就会更多的理解它。
      

  30.   

    可以定义重写同名类,我是这么理解的,感觉就是把具有相同作用的类写在一个集合里,就像一个dataset类。
      

  31.   

    您一定是高手,可是您没有看到我的题目吗??“刚学C#”,更准确的说“刚学OO(p)”,初学,遇到不懂的,就不应该问问???这年头,没有钱受歧视,没有想到,初学也受歧视,还让不让人活了???================@sdwbgg1。
    首先,我为我的言语,让你感到不安致以最诚意的歉意!!!I'm so sorry!我没有歧视任何人,不也会歧视任何人,我是最近一个月才泡上CSDN的。
    我说过,我专业非CS,你可以想象,我走的路,不会比你平坦,几乎每个人都是这样过来的。2。
    我不是高手,至多比你多写了几行代码,多看点资料而已,我非计算机科班出身,我是搞机械的,虽然现在连丁字尺都不懂得卡了^_^,3。
    我很应该高兴,看到大家的踊跃拍砖,
    每个人都会肯定,敢于提问的朋友。4。
    今天心情实在有点糟,令大家不愉快了,实在抱歉。
    Good Luck!
      

  32.   

    其实仔细看,你会发现Jinglecat先生的最上面的解答很权威,想必没有任何歧视谁的意思==============@yuxuanji您好,^_^第一子句,中性,对待每个问题,大家都需仔细哈, ^||^第二子句,高帽,不适合,我只是表达我的理解而已,纯属乱弹,第三子句,谢谢,你对我的理解 ~_~
      

  33.   

    有些override的函数是因为有特殊要求,例如页面生成所执行的事件详细的看页面生成时所执行的事件但你为页面改变语言的时候
    protected override void InitializeCulture()
        {
         }
    当改变皮肤的时候 
    protected override void  OnPreInit(EventArgs e)
    {}
    一个事件就执行那么一个事,可以慢慢试试
      

  34.   

    LZ其实不太多的去关心语言底层的东西(对于初学者)
    当然想弄明白是件好事
    个人肤浅的认为
    Virtual去重写
    就好比,父亲有吃饭的方法,儿子也有
    儿子和父亲是继承的关系,
    但是吃饭的方式方法又不同,难道你用程序模拟这个现象的时候,儿子就不叫‘吃饭’了么
    都应该叫Eating,所以,你要去重写父亲的方法,因为你们是继承关系
      

  35.   

    你的话说,可以在子类里面写个别的方法
    其实是不和逻辑的
    抽象的现实,就是父亲是Eating
    那你就是别的什么什么ing
    不和逻辑吧
    所以,我们要常常把自己的程序放在现实,看看能不能说通就对了
    面向对象么
      

  36.   

    想当初了解异步调用的时候,就是老师举了个相当生动的现实例子
    才明白的
    呵呵
    LZ Good Luck
      

  37.   

    ls,什么意思??结分,谢谢各位了。没什么说的,看了octverve(炎之脉) ( ),也体会了Jinglecat(晓风残月 >> 问题需简洁,错误要详细)的话,唯一结论是,问题必须靠自己。
     结贴。
      

  38.   

    说了半天,LZ也只是要个小程序证实virtual的作用,我在MSDN找了一个:// cs_virtual_keyword.cs
    using System;
    class TestClass
    {
        public class Dimensions
        {
            public const double PI = Math.PI;
            protected double x, y;
            public Dimensions()
            {
            }
            public Dimensions(double x, double y)
            {
                this.x = x;
                this.y = y;
            }        public virtual double Area()
            {
                return x * y;
            }
        }    public class Circle : Dimensions
        {
            public Circle(double r)
                : base(r, 0)
            {
            }        public override double Area()
            {
                return PI * x * x;
            }
        }    class Sphere : Dimensions
        {
            public Sphere(double r)
                : base(r, 0)
            {
            }        public override double Area()
            {
                return 4 * PI * x * x;
            }
        }    class Cylinder : Dimensions
        {
            public Cylinder(double r, double h)
                : base(r, h)
            {
            }        public override double Area()
            {
                return 2 * PI * x * x + 2 * PI * x * y;
            }
        }    static void Main()
        {
            double r = 3.0, h = 5.0;
            Dimensions c = new Circle(r);
            Dimensions s = new Sphere(r);
            Dimensions l = new Cylinder(r, h);
            // Display results:
            Console.WriteLine("Area of Circle   = {0:F2}", c.Area());
            Console.WriteLine("Area of Sphere   = {0:F2}", s.Area());
            Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
        }
    }
      

  39.   

    MSDN有个很好的例子,我粘贴下来,有点长,不过你仔细看过后就绝对的明白了          C# 程序员参考  
    了解何时使用 Override 和 New 关键字(C# 编程指南)  
    请参见   
     全部折叠 全部展开    语言筛选器: 全部 语言筛选器: 多个 语言筛选器: Visual Basic 语言筛选器: C# 语言筛选器: C++ 语言筛选器: J# 语言筛选器: JScript  
     Visual Basic(声明) 
     Visual Basic(用法) 
     C# 
     C++ 
     J# 
     JScript C# 允许派生类中的方法与基类中的方法具有相同的名称,只要您非常明确应如何处理新方法。下面的示例演示 new 和 override 关键字的使用。首先声明三个类:一个名为 Car 的基类以及从该基类派生的两个类 ConvertibleCar 和 Minivan。基类包含一个可将有关汽车的描述发送到控制台的方法 (DescribeCar)。派生类方法也包含一个名为 DescribeCar 的方法,该方法显示派生类的独特属性。这些方法还调用基类的 DescribeCar 方法来演示从 Car 类继承属性的方式。 为了强调区别,ConvertibleCar 类使用 new 关键字来定义,而 Minivan 类使用 override 来定义。C#  复制代码 
    // Define the base class
    class Car
    {
        public virtual void DescribeCar()
        {
            System.Console.WriteLine("Four wheels and an engine.");
        }
    }// Define the derived classes
    class ConvertibleCar : Car
    {
        public new virtual void DescribeCar()
        {
            base.DescribeCar();
            System.Console.WriteLine("A roof that opens up.");
        }
    }class Minivan : Car
    {
        public override void DescribeCar()
        {
            base.DescribeCar();
            System.Console.WriteLine("Carries seven people.");
        }
    } 现在可以编写一些代码来声明这些类的实例,并调用它们的方法以便对象能够描述其自身:C#  复制代码 
    public static void TestCars1()
    {
        Car car1 = new Car();
        car1.DescribeCar();
        System.Console.WriteLine("----------");    ConvertibleCar car2 = new ConvertibleCar();
        car2.DescribeCar();
        System.Console.WriteLine("----------");    Minivan car3 = new Minivan();
        car3.DescribeCar();
        System.Console.WriteLine("----------");
    } 正如预期的那样,输出类似如下所示:Four wheels and an engine. ---------- Four wheels and an engine. A roof that opens up. ---------- Four wheels and an engine. Carries seven people. ---------- 但是,在该代码接下来的一节中,我们声明了一个从 Car 基类派生的对象的数组。此数组能够存储 Car、ConvertibleCar 和 Minivan 对象。该数组的声明类似如下所示:C#  复制代码 
    public static void TestCars2()
    {
        Car[] cars = new Car[3];
        cars[0] = new Car();
        cars[1] = new ConvertibleCar();
        cars[2] = new Minivan();
    } 然后可以使用一个 foreach 循环来访问该数组中包含的每个 Car 对象,并调用 DescribeCar 方法,如下所示:C#  复制代码 
    foreach (Car vehicle in cars)
    {
        System.Console.WriteLine("Car object: " + vehicle.GetType());
        vehicle.DescribeCar();
        System.Console.WriteLine("----------");
    } 此循环的输出如下所示:Car object: YourApplication.Car Four wheels and an engine. ---------- Car object: YourApplication.ConvertibleCar Four wheels and an engine. ---------- Car object: YourApplication.Minivan Four wheels and an engine. Carries seven people. ---------- 注意,ConvertibleCar 说明与您的预期不同。由于使用了 new 关键字来定义此方法,所调用的不是派生类方法,而是基类方法。Minivan 对象正确地调用重写方法,并产生预期的结果。若要强制一个规则,要求从 Car 派生的所有类都必须实现 DescribeCar 方法,则应创建一个新的基类,将方法 DescribeCar 定义为 abstract。抽象方法不包含任何代码,仅包含方法签名。从此基类派生的任何类都必须提供 DescribeCar 的实现。有关更多信息,请参见抽象。请参见
    参考
    对象、类和结构(C# 编程指南)概念
    C# 编程指南
    使用 Override 和 New 关键字控制版本(C# 编程指南)
     要提出有关“帮助”或本产品其他功能的建议或错误报告,请转到反馈站点。 
      

  40.   

    我也想不明白,找不到那个例子一定要用Virtual才能实现的,JAVA里面就没有virtual,override 这东西。
      

  41.   

    个人理解,virtual在基类定义一个方法,然后子类用override来重写基类的方法,可以用base.方法来继承基类的方法,也可以直接重写来定义一个同名的方法使用时,就会用到子类重写的方法了,如果子类没有重写,就会用父类的virtual方法举例,virtual方法:射门 override方法:射门,用左脚射门或直接override方法: 改写父方法,用头顶进去
      

  42.   

    真替楼主着急,我想楼主的问题应该是:
    写了个父类A,里边有方法b(b方法并没有加virtual)
    子类继承A 后 写了个同样的方法b 楼主的疑问可能是 我在子类同样可以重写父类的b方法,为什么还有virtual存在的必要?
    如果楼主的问题是这样的话,我说说我的理解
    我上边的那种写法并不叫重写,专业点的话叫做 我在子类中隐藏了父类的B成员而重写方法,必须要加override申明,而如果父类方法没有申明为可重写,那么在编译时就会报错(无法重写)如果你质疑 ”重写“存在的必要,请去看看多态方面的资料
      

  43.   

    有两个 class,  A 和 B,  B derived from Aclass A
    {
    public:
        HERE_IS_FOR_virtual void aa(){ MessageBox("是 A 类把我输出来的");
    }class B: A
    {
    public:
        void aa(){ MessageBox("是 B 类把我输出来的");
        void bb(){ a();};
        void bbbb(){ A::aa();}
    }void A_function(void)
    {
        A a;
        B b;
        
        a.aa();  //"是 A 类把我输出来的"
        b.aa();  //"是 B 类把我输出来的"
        b.bb();  //"是 A 类把我输出来的"
        b.bbbb();  //"是 A 类把我输出来的"
    }
    在A_function中,aa()是直接call by reference, compiler 知道得非常清楚,没有ambiguity。但是, 有除了直接call by reference, C++语言中,还可以call by pointer。void B_function(A* pa)
    {
        pa->aa();
    }
    在 B_function 中, pa 可以是A*, 也可以是(A*)B*, 这是完全合乎语法的。  在(A*)B*这种情况下, 如果在class A 中, HERE_IS_FOR_virtual 换成 virtual, 把aa()声明成virtual function, 那么, pa->aa() call的是 class B 的aa(), 输出"是 B 类把我输出来的",  如果HERE_IS_FOR_virtual换成空气, 也就是aa()不是virtual, 那么pa->aa() call的是 class A 的aa(), 输出"是 A 类把我输出来的"。在A_function中, 有没有virtual都一样, 在B_function中, 天差地别,  virtual function 在 B_function 中的用法就是 Polymophism
      

  44.   

    class B: A
    {
    public:
      void aa(){ MessageBox("是 B 类把我输出来的");
      void bb(){ a();};     ----->更正为, void bb(){ aa();}; 
      void bbbb(){ A::aa();}
    }void A_function(void)
    {
      A a;
      B b;
        
      a.aa(); //"是 A 类把我输出来的"
      b.aa(); //"是 B 类把我输出来的"
      b.bb(); //"是 A 类把我输出来的"        ---->更正为  "是 B 类把我输出来的" 
      b.bbbb(); //"是 A 类把我输出来的"
    }特此 DEBUG , 结帖
      

  45.   

    简单一句话,加virtaul是为了实现多态,实现多态不止体现在子类实现自己方法的同时还体现在子类对象的实现,差别自己看看     static void Main(string[] args)
            {
                
                Person[] per = new Person[5];            Chinese cn1 = new Chinese();
                Chinese cn2 = new Chinese();
                Japanese jp1 = new Japanese();
                Japanese jp2 = new Japanese();
                Beijing bj1 = new Beijing();
                per[0] = cn1;
                per[1] = cn2;
                per[2] = jp1;
                per[3] = jp2;
                per[4] = bj1;           //  Chinese[]={}
               //      Japanese[]={};
                for (int i = 0; i < per.Length; i++)
                {
                    //if (per[i] is Chinese)
                    //{
                    //    Chinese c = per[i] as Chinese;
                    //    c.ShowNationality();
                    //}
                    //else if (per[i] is Japanese)
                    //{
                    //    Japanese j = (Japanese)per[i];
                    //    j.ShowNationality();
                    //}if                per[i].ShowNationality();
                
                }            //Person p = new Chinese();
                //Chinese p = new Chinese();
                //p.go();
                Console.ReadKey();
            }
        }
        //class Person
        //{
        //    public string Name
        //    {
        //        get;
        //        set;
        //    }    //    public int Age
        //    {
        //        get;
        //        set;
        //    }    //    //
        //    virtual public void ShowNationality()
        //    {    //    }    //}    //class Chinese : Person
        //{
        //    public string HuKou
        //    {
        //        get;
        //        set;
        //    }    //    //显示国籍
        //    public override void ShowNationality()
        //    {
        //        base.ShowNationality();
        //        // Console.WriteLine("中国");
        //    }
        //}    //class Japanese : Person
        //{
        //    public void PoFu()
        //    {
        //        Console.WriteLine("各种颜色!");
        //    }    //    public override void ShowNationality()
        //    {
        //        Console.WriteLine("日ben!");
        //    }
        //}
        //以下是关于抽象方法与抽象类
        abstract class Person
        {
            public string Name
            {
                get;
                set;
            }        public int Age
            {
                get;
                set;
            }
            public void sayHello()
            {
                Console.WriteLine("Hi,everybody!");
            }
            //抽象放
            virtual public void ShowNationality() { }        virtual public void test()
            {
            }        virtual public void go()
            {
                Console.WriteLine("go somewhere");
            }    }    class Chinese : Person
        {
            public string HuKou
            {
                get;
                set;
            }        public new  void go()
            {
                Console.WriteLine("go 饶平!");
            }
            //显示国籍
            public new void ShowNationality()
            {
                //base.ShowNationality();//抽象类不能实例化,所以不能通过base来调用。
                Console.WriteLine("中国");
                //this.sayHello();
            }
        }    class Japanese : Person
        {
            public void PoFu()
            {
                Console.WriteLine("各种颜色!");
            }        public override void ShowNationality()
            {
                Console.WriteLine("日ben!");
            }
        }    class Beijing : Chinese
        {        public new void ShowNationality()
            {
                Console.WriteLine("我是很牛13的北京人!");
            }    }
    }