多态性和铸造

use*_*717 12 c# polymorphism virtual overriding

我想了解c#中的多态性,所以通过尝试几个构造我想出了以下情况:

class Shape
{
    public virtual void Draw()
    {
        Console.WriteLine("Shape.Draw()");
    }
}

class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Circle.Draw()");
    }
}
Run Code Online (Sandbox Code Playgroud)

我理解为了将Draw()消息发送到几个相关的对象,所以他们可以根据自己的实现行事我必须更改(在这种情况下)形状'指向'的实例:

Shape shape = new Circle();
shape.Draw(); //OK; This prints: Circle.Draw()
Run Code Online (Sandbox Code Playgroud)

但是,为什么,当我这样做时:

Circle circle = new Circle();
circle.Draw(); //OK; This prints: Circle.Draw()

Shape shape = circle as Shape; // or Shape shape = (Shape)circle;
shape.Draw();
Run Code Online (Sandbox Code Playgroud)

它打印:"Circle.Draw()"

为什么在演员表之后调用Circle.Draw()而不是Shape.Draw()?这是什么原因?

Ale*_*kov 13

转换不会更改运行时对象类型以及每个实例具有的特定虚拟方法的实现.

请注意,以下2个案例中您的样本相同:

Shape shape = new Circle();
shape.Draw(); //OK; This prints: Circle.Draw()
Run Code Online (Sandbox Code Playgroud)

和:

Circle circle = new Circle();
Shape shape = circle as Shape;
shape.Draw();
Run Code Online (Sandbox Code Playgroud)

第一个基本上是第二个的较短版本.


小智 8

正如其他人所提到的,投射对象并不会改变实际的实例; 相反,cast允许变量从对象层次结构中的较高位置开始假设实例的特征子集.

要说明为什么需要以这种方式工作,请考虑以下示例:

//Some buffer that holds all the shapes that we will draw onscreen
List<Shape> shapesOnScreen = new List<Shape>();

shapesOnScreen.Add(new Square());
shapesOnScreen.Add(new Circle());

//Draw all shapes
foreach(Shape shape in shapesOnScreen)
{
    shape.Draw();
}
Run Code Online (Sandbox Code Playgroud)

在foreach循环中调用Draw()将调用派生实例的Draw()方法,即Square.Draw()和Circle.Draw().在此示例中,这允许您绘制每个单独的形状,而无需确切知道您在运行时绘制的形状.你只知道你需要一个形状,让形状处理它的绘制方式.

如果不是这种情况(这适用于其他语言的继承,而不仅仅是C#),那么除了Shape.Draw()之外你将无法使用任何东西.


eva*_*nal 6

您将覆盖继承类中的方法,因此无论您是否引用不太具体的基类,它都将始终是调用的版本.

如果要调用版本,则Shape需要类型的实例,Shape而不仅仅是该类型的引用.