Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop CLR如何知道对从抽象基继承的派生类调用哪个方法?_Oop_Polymorphism_Typing - Fatal编程技术网

Oop CLR如何知道对从抽象基继承的派生类调用哪个方法?

Oop CLR如何知道对从抽象基继承的派生类调用哪个方法?,oop,polymorphism,typing,Oop,Polymorphism,Typing,我遇到以下情况,我想知道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 ov

我遇到以下情况,我想知道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
Shape square=new square();
形状圆=新圆();
列表形状=新列表{正方形,圆形};
foreach(形状中的形状s)
{
Console.WriteLine(s.PrintName());
}
//输出:
//方格
//圈

那么,即使我们在基类型上调用该方法,我们如何能够在派生类上调用该方法呢?我不知道这是如何处理的。

当您实例化
Shape square=new square()时
,事实上,
square
实际上是一个
square
实际上是完整的。请记住,变量
square
实际上是对真实对象的引用。引用类型(在本例中,
Shape
)必须是与实例化类型(
Square
)相同的类或继承层次结构上更高的类,正如您在这里看到的那样

实例化之后,当编译器看到
square
时,它首先知道它是抽象类型
Shape
,因为这是引用的类型。因此,它必须是形状的子类型,因为您不能实例化抽象对象。既然你说了
newsquare()编译器将知道确切的类型。同样,对象的确切类型不会因为将其指定给baser(更基本)类型而丢失


调用
square.PrintName()时square
是用抽象类型
Shape
声明的,它有一个方法
PrintName()
,也标记为abstract。这告诉编译器在子类中查找相同的精确方法。如果在子类中找到
PrintName()
,则一切正常-将执行正确的函数。如果没有,则会出现错误,因为基类定义中的单词abstract要求您实现它。

当您实例化
Shape square=new square()时
,事实上,
square
实际上是一个
square
实际上是完整的。请记住,变量
square
实际上是对真实对象的引用。引用类型(在本例中,
Shape
)必须是与实例化类型(
Square
)相同的类或继承层次结构上更高的类,正如您在这里看到的那样

实例化之后,当编译器看到
square
时,它首先知道它是抽象类型
Shape
,因为这是引用的类型。因此,它必须是形状的子类型,因为您不能实例化抽象对象。既然你说了
newsquare()编译器将知道确切的类型。同样,对象的确切类型不会因为将其指定给baser(更基本)类型而丢失


调用
square.PrintName()时square
是用抽象类型
Shape
声明的,它有一个方法
PrintName()
,也标记为abstract。这告诉编译器在子类中查找相同的精确方法。如果在子类中找到
PrintName()
,则一切正常-将执行正确的函数。如果没有,则会出现错误,因为基类定义中的单词abstract要求您实现它。

因为CLR的类型安全功能,它确保在创建Foo实例时,您不能将其视为Bar,在运行时它总是知道对象的类型。因此,当您对图形调用PrintName()时,它知道它是处理正方形还是圆形


请注意,由于GetType()是非虚拟的,因此无法重写它,因此不能伪造对象的类型。

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


请注意,由于GetType()是非虚拟的,因此无法重写它,因此不能伪造对象的类型。

我认为编译器的工作不是查找虚拟方法实现。这项工作是在运行时完成的。虚拟机负责这项工作,而不是编译器。即使您引用的是JIT编译器,它仍然不准确。编译器只是检查有问题的类型是否具有相应的方法,并将其余工作(动态查找)留给运行时。我认为编译器的工作不是查找虚拟方法实现。这项工作是在运行时完成的。虚拟机负责这项工作,而不是编译器。即使您引用的是JIT编译器,它仍然不准确。编译器只是检查有问题的类型是否具有相应的方法,并将其余工作(动态查找)留给运行时。