【问题标题】:Why are the last 2 lines outputting what they are?为什么最后两行输出它们是什么?
【发布时间】:2021-02-22 14:48:26
【问题描述】:

谁能帮我理解

  1. 这个说法是否正确:BaseClass bcdc = new DerivedClass(); 表示 bcdc 是 BaseClass 类的类型,它的值是 DerivedClass 对象的类型?另外,这意味着什么?为什么要像 DerivedClass dc = new DerivedClass() 那样实例化一个对象,而不是让类类型与被实例化的新对象相同?
  2. 为什么要bcdc.Method1() => Derived-Method1。是不是因为使用了关键字override,才这么覆盖了虚Method1?
  3. 为什么bcdc.Method2() => Base-Method2。我很困惑,因为 DerivedClass 中的新关键字应该隐藏 Base-Method2?我认为这就是 new 关键字的功能。
class BaseClass  
{  
    public virtual void Method1()  
    {  
        Console.WriteLine("Base - Method1");  
    } 
    public void Method2()  
{  
    Console.WriteLine("Base - Method2");  
} 
}  
  
class DerivedClass : BaseClass  
{  
    public override void Method1()  
{  
    Console.WriteLine("Derived - Method1");  
}  
    public new void Method2()  
    {  
        Console.WriteLine("Derived - Method2");  
    }  
}
class Program  
{  
    static void Main(string[] args)  
    {  
        BaseClass bc = new BaseClass();  //bc is of type BaseClass, and its value is of type BaseClass
        DerivedClass dc = new DerivedClass();  //dc is of type DerivedClass, and its value is of type DerivedClass
        BaseClass bcdc = new DerivedClass();  //bcdc is of type BaseClass, and its value is of type DerivedClass.
                     
        bc.Method1();  //Base - Method1 
        bc.Method2();  //Base - Method2
        dc.Method1();  //Derived - Method1
        dc.Method2();  //Derived - Method2 
        bcdc.Method1(); //Derived - Method1. ??
        bcdc.Method2(); //Base - Method2.  ??
    }   
} ```

【问题讨论】:

  • 考虑一个绘图应用程序。它有一个基类DrawObject 和几个派生类:RectangleCircleLine。屏幕在List<DrawObject> drawList 中管理。当用户在屏幕上创建一个新圆圈时,代码会执行类似于drawList.Add(new Circle(params)); 的操作,这实际上就是您所看到的(创建基类的新实例并将其分配给类型为基类的引用。在DrawObject 类,有一个标记为virtual 的方法称为Draw。每个子类覆盖该方法。绘制所有内容只是循环并调用Draw
  • docs.microsoft.com/en-us/dotnet/csharp/language-reference/… - 它使用与我相同的示例。还要考虑一个管理List<Animal> pets 集合的应用程序。子类可以包括DogCatBird。每个子类都覆盖了虚拟方法Speak。狗会说“汪”,猫会说“喵”,鸟会说“唧唧”。这是一个易于在简单的控制台应用中创建和测试的示例。
  • @Flydog57 感谢您的链接和解释。我从 Microsoft 文档中获得了我的示例。docs.microsoft.com/en-us/dotnet/csharp/programming-guide/… 我了解覆盖和虚拟的使用,但我不明白为什么bcdc.Method2(); 输出 Base-Meth DerivedClass Method2() 具有新的关键字。我希望输出是 Dervied-Method2。你能指出我理解这种行为的正确方向吗?
  • 当您将 new 关键字添加到这样的方法中时,您是在说“是的,我知道我的基类有一个名为 Method2 的方法,但我想要一个名为Method2 有不同的含义。考虑一个继承自 CowboyCowboyArtist 类。Cowboy 类有一个名为 Draw 的方法,这意味着 从皮套中拔出你的枪。CowboyArtist类希望Draw 表示制作绘图,因此它用new 标记其实现。这两个方法具有相同的名称,但语义不同,并且根本不相关。

标签: c# inheritance polymorphism


【解决方案1】:

也就是说bcdc是BaseClass类的类型,它的值是DerivedClass对象类型的?

是的。但是,我更愿意将其称为 DerivedClass objectBaseClass reference

另外,这意味着什么?为什么要像这样实例化一个对象,而不是像在 DerivedClass dc = new DerivedClass() 中那样让类类型与被实例化的新对象相同?

一种情况是您想调用explicit interface method。但是,如果您调用一个方法,则会发生非常相似且更常见的情况:MyMethod(BaseClass bcdc)

在这个简单的程序中,所有类型在编译时都很容易知道。但是对于较大的程序就不是这样了,一个方法带有一个BaseClass 参数,它可以有一堆不同的实现,并且在编译代码时可能不知道所有的实现。

为什么 bcdc.Method1() => Derived-Method1。是不是因为使用了关键字override,所以才覆盖了虚Method1?

是的,对于标记为virtual 的方法,编译器将插入一个检查,根据实际的对象类型,即DerivedClass,将方法调用转发给被覆盖的方法。这有时称为虚拟调度dynamic dispatch。 IE。该方法将在运行时根据对象类型动态选择。

为什么 bcdc.Method2() => Base-Method2。我很困惑,因为 DerivedClass 中的新关键字应该隐藏 Base-Method2?我认为这是 new 关键字的功能。

Method2 不是虚拟的,所以不会有动态调度。所以引用类型,即BaseClass,将用于确定被调用的方法。这称为static dispatch,即调用的方法可以在编译时静态确定。

【讨论】:

  • 这很棒。非常感谢。我将研究静态和动态调度以进一步了解。
猜你喜欢
  • 1970-01-01
  • 2017-09-08
  • 2010-12-22
  • 2014-08-13
  • 1970-01-01
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 2011-08-03
相关资源
最近更新 更多