将派生类对象分配给父类引用

当我看到时,我总是感到困惑:

Parent ref = new Child(); 

其中Child类扩展Parent。

  1. 对象ref如何在内存中看起来像?
  2. 如何处理虚拟方法? 非虚?
  3. 它与以下内容有何不同:
 Child ref = new Child(); 

对象在内存中的外观如何?

你的问题不清楚。 有两个相关的内存位置。 该变量与存储位置相关联。 该存储位置包含对另一个存储位置的引用

变量的存储位置通常实现为四字节或八字节整数,其中包含“托管指针” – 垃圾收集器已知的内存地址。

对象的内存布局也是CLR的实现细节。 与对象关联的内存缓冲区将包含对象的所有数据 – 字段的所有值以及诸如此类的东西。 它还包含对另一个内存位置的引用,即对象的虚函数表

然后,虚函数表(vtable)包含更多引用 ,这次引用引用与最派生类型的对象关联的方法。

如何处理虚拟方法? 非虚?

通过从变量中查找对象引用,然后查找vtable,然后在vtable中查找方法,然后调用该方法来执行虚方法。

非虚方法不是通过vtable调用的,因为它们在编译时是已知的。

它与……有什么不同?

在对象上调用的非虚方法将根据变量的类型调用方法的版本。 调用该对象的虚方法将根据该变量引用的对象的类型调用该方法的版本。

如果不是很清楚,您可能需要阅读我的文章,该文章解释了如何使用没有它们的语言“模拟”虚拟方法。 如果您能够理解如何使用没有它们的语言自己实现虚拟方法,那么这将有助于您了解我们实际实现虚拟方法的方式。

http://blogs.msdn.com/b/ericlippert/archive/2011/03/17/implementing-the-virtual-method-pattern-in-c-part-one.aspx

ref是一个Child对象。 在Child类上调用虚方法。 但是,仅在Child类中定义的方法在分配给Parent对象时不可见。

如果foo()不是虚拟的,那么编译将根据变量ref的声明类型选择一个方法。 如果你有Parent ref = new Child(); 然后将调用Parent.foo() 。 如果你有Child ref = new Child(); 然后将调用Child.foo() 。 当然,在这种情况下,C#编译器会要求您在Child.foo()的声明中使用new来表示您要在Parent隐藏实现。

我想ref只包含可以找到引用的Child对象的地址。 如果调用虚方法,则调用的实际方法取决于对象的动态类型( Child ); 如果调用非虚方法,则取决于静态类型( Parent )。 它与Child ref = ...不同,因为在那一个中​​,静态类型是Child而不是Parent

我希望这不是功课:)

可以这样想(假设Parent不是抽象类)

 Parent ref = new Child(); 

 Parent ref = new Parent(); 

大致相同,除了在Child中重写的虚拟方法将被调用,而不是后者。

声明对象的类型将确定可用的方法。 声明一个对象是一个不像你实例化它的特定类型 – 前一种情况 – 影响在运行时调用哪些方法,但前提是这些方法被声明为abstract或virtual。

无论哪种情况,想象一下你在ref上调用了方法foo 。 运行时在类Parent上很好的方法foo 。 然后,运行时将查看foo为虚拟(或抽象)。 如果foo不是虚拟的或抽象的,那么运行时会调用foo Parent定义的那个,然后完成它。 但是,如果foo 虚拟的或抽象的,运行时将检查ref是否真的被实例化为覆盖foo的更具体的类型。 如果是这样,它会称之为foo