0

我有以下情况,我想知道 CLR 如何知道要调用哪个方法:

public abstract class Shape
{
    public abstract String PrintName();
}

public sealed class Square : Shape
{
    public override String PrintName() { return "Square"; }
}

public sealed class Circle : Shape
{
    public override String PrintName() { return "Circle"; }
}

然后我实例化每个形状:

Shape square = new Square();   
Shape circle = new Circle();
List<Shape> shapes = new List<Shape> { square, circle };

foreach (Shape s in shapes)
{
    Console.WriteLine(s.PrintName());   
}

// Output:
// Square
// Circle

那么,即使我们在基类型上调用方法,我们如何才能在派生类上调用方法呢?我很困惑这是如何处理的。

4

2 回答 2

2

由于 CLR 的类型安全特性,可确保在创建 Foo 的实例时不能将其视为 Bar,因此在运行时它始终知道对象的类型。因此,当您在形状上调用 PrintName() 时,它知道它处理的是方形还是圆形。

请注意,由于 GetType() 是非虚拟的,它不能被覆盖,因此您不能欺骗对象的类型。

于 2012-12-11T23:52:54.287 回答
1

当你实例化时,真的是一个真的Shape square = new Square();事实是完整的。请记住,变量确实是对真实对象的引用。引用类型(在本例中为)必须与实例化类型 ( ) 相同或在继承层次结构中更高,正如您在此处所做的那样。squareSquaresquareShapeSquare

实例化之后,当编译器看到 时square,它首先知道它是抽象类型Shape,因为那是引用的类型。因此,它必须是 Shape 的子类型,因为您无法实例化抽象对象。既然你说new Square();编译器会知道确切的类型。同样,对象的确切类型不会因为您将其分配给基本(更基本)类型而丢失。

当你调用square.PrintName();时,编译器首先看到square是用抽象类型声明的Shape,它有一个方法PrintName(),也标记为抽象。这告诉编译器在子类中寻找相同的方法。如果它PrintName()在子类中找到,一切都很好 - 将执行正确的函数。如果没有,你会得到一个错误,因为基类定义中的抽象词要求你实现它。

于 2012-12-11T23:51:14.363 回答