简单的C#OOP继承查询

简单的C#OOP继承查询,c#,visual-studio,oop,inheritance,C#,Visual Studio,Oop,Inheritance,鉴于以下类别: interface IShape { void Draw(); } class Rectangle : IShape { public void Draw() { } } class Square : Rectangle { public new void Draw() { } } 有人能解释一下第二种抽签方法会发生什么吗 Rectangle rect = new Rectangle(); rect.Draw(); rect = new Squar

鉴于以下类别:

interface IShape
{
    void Draw();
}

class Rectangle : IShape
{
    public void Draw() { }
}

class Square : Rectangle
{
    public new void Draw()  { }
}
有人能解释一下第二种抽签方法会发生什么吗

Rectangle rect = new Rectangle();
rect.Draw();
rect = new Square();
rect.Draw();

一开始,我会说将调用Square类的Draw方法,但当我将其输入VS2013时,矩形类的Draw方法被调用。

它将调用
Draw
矩形版本

这是因为变量
rect
在编译时的类型为
Rectangle
。由于您已通过
new
重写了
Square
Draw
方法,因此运行时无法在运行时查找
Draw
Square
版本-这将是在虚拟表或V表中的查找,在本例中不存在,因为
Draw
不是
Virtual

请注意,下面将调用
Draw

Square sq = new Square();
sq.Draw();
因为
sq
在编译时是已知的
Square

如果要在
矩形
内将
绘制
设为
虚拟
,并将
新建
更改为
覆盖
,则原始代码将调用
正方形。绘制
。这是允许的,即使
Draw
是接口方法的实现

也可以制作一种新的接口方法。考虑以下事项:

internal interface IShape
{
    void Draw();
}

internal class Rectangle : IShape
{
    public void Draw() { }
}

internal class Square : Rectangle, IShape
{
    public new void Draw() { }
}
在这种情况下,代码

IShape rect = new Rectangle();
rect.Draw();
rect = new Square();
rect.Draw();

将调用第二个表单。

Square
类中,关键字
new
告诉编译器这是一个全新的方法,恰好与继承的方法具有相同的签名。因为这是巧合,所以它不应该重写继承的方法

在这种情况下,当通过
Square
变量调用
Draw()
时,编译器将选择新方法。如果在这种情况下它没有选择新的方法,那么如果你仔细考虑的话,你根本没有办法调用它。如果要调用旧的
Draw()
,仍然可以通过
矩形
变量调用它(即使在同一实例上)

这称为,您可以在任何方法上执行。您不会经常需要它——如果可能的话,您应该避免它,因为虽然它的语义定义良好,但它会使您的源代码有点混乱


相反,如果希望表示这不是巧合,并且您有意使用相同的签名覆盖继承的方法,则应在新方法上使用关键字
override
。在这种情况下,在对象上调用
Draw()
时,无论从哪个变量调用它,都会得到用于创建该对象的类的
Draw()
版本(
new Square()
new Rectangle()
,等等)

请记住,被重写的方法必须首先允许自己被重写。为此,必须首先将其标记为
virtual
first-不能重写未标记为
virtual
的方法


正如关键字所说,这被称为。您将经常看到并使用此方法,因为它启用了,这是面向对象编程的核心概念之一。

如果
Draw
方法是虚拟的,那么将使用对象的实际类型来确定要调用的方法,即
Square.Draw
方法


由于该方法不是虚拟的,因此决定调用哪个方法的是引用的类型,即
矩形.Draw
方法。

当使用
new
而不是
override
时,该方法不会被覆盖,而是隐藏

class Animal
{
    public virtual void MakeSound() { Console.WriteLine("Animal called"); } 
}

class Dog : Animal
{
    // Note: You can not use override and new in the same class, on 
    // the same method, with the same parameters.  This is just to 
    // show when "new" takes effect, and when "override" takes effect.
    public override void MakeSound() 
    { 
        Console.WriteLine("Animal's MakeSound called for dog"); 
    } 

    public new void MakeSound()
    {
        Console.WriteLine("Dog's MakeSound called"); 
    }
}

public static class Program
{
    public static void Main(string[] args)
    {
        Dog dogAsDog = new Dog();
        Animal dogAsAnimal = dogAsDog;

        // prints "Dog's MakeSound called"
        dogAsDog.MakeSound();

        // prints "Animal's MakeSound called for dog"
        dogAsAnimal.MakeSound();
    }
}

由于已将其装箱为矩形,并且Square类隐藏而不是覆盖矩形的Draw(),因此第二个调用将执行矩形的Draw方法。

研究覆盖与隐藏。这里有大量的资料。这实际上将开始深入探讨一些关于方法本身如何被调用和绑定的深层概念。将虚拟表格添加到您的研究中。这是一个对所有程序开放的问题。让优雅的代码战斗开始吧。