将派生类对象分配给父类引用
本文关键字:父类 引用 分配 对象 派生 | 更新日期: 2023-09-27 18:16:47
当我看到:
Parent ref = new Child();
其中子类扩展父类。
- 对象在内存中
ref
是什么样子的? - 如何处理虚拟方法?非虚拟方法?
- 它与以下方面有何不同:
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 中被覆盖的虚拟方法将在前者中调用,而不是后者。
将对象声明为的类型将确定哪些方法在其上可用。 将对象声明为比实例化对象更不具体的类型(前一种情况(可能会影响在运行时调用哪些方法,但前提是这些方法声明为抽象或虚拟。
无论哪种情况,假设您在 ref 上调用了一个foo
的方法。 运行时将对类Parent
进行foo
方法。 然后,运行时将查看foo
是虚拟的(还是抽象的(。 如果foo
不是虚拟的或抽象的,运行时将立即调用 Parent 定义的foo
,并完成它。 但是,如果foo
是虚拟的或抽象的,运行时将检查 ref 是否真的实例化为覆盖foo
的更具体的类型。 如果是这样,它将称之为foo