讨教一个虚方法的问题

.Net技术 码拜 8年前 (2016-04-28) 731次浏览
class class1
    {
        public void m()
        {
            Console.WriteLine("这是一个方法");
        }
        public virtual void vm()
        {
            Console.WriteLine("这是一个虚方法");
        }
    }
    class class2 : class1
    {
        public new void m()
        {
            Console.WriteLine("这是继承类的方法");
        }
        public override void vm()
        {
            //base.vm();
            Console.WriteLine("这是继承类的虚方法");
        }
    }
    class class3 : class2
    {
        public new /*override*/ void vm()
        {
            //base.vm();
            Console.WriteLine("这是第三个继承类的虚方法");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            class1 c1 = new class1();
            c1.m();
            c1.vm();
            Console.WriteLine();
            class2 c2 = new class2();
            c2.m();
            c2.vm();
            Console.WriteLine();
            class1 c3 = new class2();
            c3.m();
            c3.vm();
            Console.WriteLine();
            class3 c4 = new class3();
            c4.m();
            c4.vm();
            Console.WriteLine();
            class1 c5 = new class3();
            c5.m();
            c5.vm();
            Console.ReadKey();
        }
    }

/*
输出
这是一个方法
这是一个虚方法
这是继承类的方法
这是继承类的虚方法
这是一个方法
这是继承类的虚方法
这是继承类的方法
这是第三个继承类的虚方法
这是一个方法
这是继承类的虚方法
*/
问一下为什么c5.vm();输出的是”这是继承类的虚方法”?这个地方不太明白,还请高手能解释清楚一点,谢谢.

解决方案

2

去掉override就相当于new。

2

假如派生类中的方法前面没有 new 或 override 关键字,则编译器将发出警告,该方法将有如存在 new 关键字一样执行操作。 ——摘自MSDN。

5

这个解释不了,要解释得花一大堆的口水
本人去看《你必须知道的.net》
http://www.cnblogs.com/anytao/archive/2007/09/10/must_net_15.html
讨教一个虚方法的问题
看明白这个图,看明白继承后对象的内存分布和方法表怎么指向的

3

至于你那个疑问请百(谷)度(哥)“对象方法就近查找原则”

4

没有仔细看你的代码。不过告诉你一个原则,我们是严禁写 new 来重载方法的。假如你的 class3 明知道本人不是真正重写 vm方法,而是另起一个重名的私有方法,它还“装”什么vm方法,莫非你不知道为 class3 的那个私有方法起名为 vm2 或别的名字吗?
为什么明知道命名冲突,非要用new 语法来起一个重名的方法?
这个 new 语法是 c#的糟粕。是15年前从c++中学来的。他除了让你迷惑,没有任何真正的用处。
面相对象程序设计有“五大原则”,其中第一条原则就是说,子类所重写的 vm 方法必须能经过父类的测试环境去检验。例如信用卡假设分为3大类,每一大类都有一点区别,然后每一个大类又分为上百种小类。在编程开发中,每一种小类的信用卡,都应该能拿到通用的针对“信用卡”的测试机上测试通过。
假设一个信用卡有“可以当饼干吃”的新特性,它何必要取一个跟通用信用开的特性术语重名的名字来命名?仅仅为了显得本人“与别的信用卡有点不一样”吗?那也应该遵循继承、多态的基本原则啊?!
实际上 new 语法是 c# 代码中的糟粕。我们严禁写这种代码(而是要求你把 class3 的 vm 方法重新命名)。教科书上假如就事论事地简单介绍这个 new 语法、写了例子,然后了事,是对这个争议问题太不负责任了,对编程开发读者不负责任。原因是这个 new 是破坏面向对象基本原则的东西,是个很大的毛病,不是小问题。

4

引用:

问一下为什么c5.vm();输出的是”这是继承类的虚方法”?这个地方不太明白,还请高手能解释清楚一点,谢谢.

new 是掐断继承链条、只定义一个重名的私有方法的语法。而你的代码

        public new /*override*/ void vm()
        {
            //base.vm();
            Console.WriteLine("这是第三个继承类的虚方法");
        }

这代码执行时的输出完全是本人骗本人。这里哪有继承了?这里明明是截断了继承,new 了一个新的重名的 vm 方法啊。所以你应该写

        public new /*override*/ void vm()
        {
            //base.vm();
            Console.WriteLine("这不是第三个继承类的虚方法,而是截断了继承之后的私有方法");
        }

这样写代码,你调试时才不会被本人骗了。

3

引用:

问一下为什么c5.vm();输出的是”这是继承类的虚方法”?这个地方不太明白,还请高手能解释清楚一点,谢谢.

c5 定义为 Class,所以它最终执行的是 class2 的 vm 方法。这个是很正常的。
无论怎么样你能看到,假如不写 new 则什么误会都不会有。class 完全可以将私有方法 vm 重新命名,没有必要重名、捣乱。

3

c5 定义为 class1,所以它最终执行的是 class2 的 vm 方法。这个是很正常的。
无论怎么样你能看到,假如不写 new 则什么误会都不会有。class3 完全可以将私有方法 vm 重新命名,没有必要重名、捣乱。
你本人在写 class3 的那个重名的私有方法 vm 内部的代码时若清醒一点,也会觉得这个 new 语法真的是给调试再捣乱,而并没有支持面向对象的继承和多态的基本机制。

4

class1 c5 = new class3();
虽然你把他声明为 class1,但他(new class3())依然是 class3 类型
只是只能使用 class1 才有的属性和方法
class3.vm 是 new 的,自然不在 class1 中。因此就使用了 class2.vm

5

c1 = new class1();
自然 c1.vm() 是 class1 本人的
本人已经说了,虽然你把 c5 声明为 class1(那是原因是 class3 是 class1 子类,否则是要出错的),但并没有改变 c5 是 class3 本质
假如你不是 public new /*override*/ void vm()
而是 public override void vm()
的话,那就会是 Console.WriteLine(“这是第三个继承类的虚方法”); 了
而你现在的 public new void vm() 中,写到 Console.WriteLine(“这是第三个继承类的虚方法”); 反而是错误的
原因是这个 vm 方法不是继承来的,而是 class3 本人的(虽然和父类的 vm 方法重名)

5

原因是 class2 继承了 class1,并重写了 vm 方法
而 class3 继承了 class2,并覆盖了 vm 方法
由于 c5 实际上是 class3 类型,所以从 class1 的角度上看,只能看到 class2 重写的方法
这样能理解吗?

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明讨教一个虚方法的问题
喜欢 (0)
[1034331897@qq.com]
分享 (0)