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

时间:2011-12-05 19:49:11

标签: c# oop inheritance polymorphism

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

Parent ref = new Child();

其中Child类扩展Parent。

  1. 对象ref在内存中的样子如何?
  2. 如何处理虚拟方法?非虚拟?
  3. 与以下内容有何不同:
  4. Child ref = new Child();
    

4 个答案:

答案 0 :(得分:6)

  

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

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

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

对象的内存布局也是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

答案 1 :(得分:2)

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

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

答案 2 :(得分:0)

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

我希望这不是作业:)。

答案 3 :(得分:0)

以这种方式思考(假设Parent不是抽象类)

Parent ref = new Child();

Parent ref = new Parent();

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

您声明对象的类型将确定哪些方法可用。声明一个对象是一个不太具体的类型而不是你实例化它 - 前一种情况 - 可以影响在运行时调用哪些方法,但只有在声明了那些方法的情况下作为抽象或虚拟。

在任何一种情况下,假设您在ref上调用了方法foo。运行时可以在类foo上使用方法Parent。然后,运行时将查看foo是否为虚拟(或抽象)。如果foo不是虚拟的或抽象的,那么运行时会调用foo父定义然后在那里,并完成它。但是,如果foo 虚拟或抽象,则运行时会检查ref 是否真的实例化为覆盖foo的更具体类型。如果是这样,它会调用 foo