【问题标题】:What does Virtual and Override do behind the sceneVirtual 和 Override 在幕后做了什么
【发布时间】:2010-11-21 13:43:19
【问题描述】:

我刚开始了解 Virtual 和 Override 是用于(我找不到这么久的用途)。 现在我在工厂模式中使用它们。所以我的问题是 Virtual 和 Override 在幕后做了什么?我愿意研究 IL 和机器代码。

【问题讨论】:

    标签: c# virtual overriding


    【解决方案1】:

    我无法为您提供关于它是如何在 IL 中完成的任何见解,但基本理论很简单。

    当编译器看到 virtual 方法声明时,它不会将该方法附加到类,而是将其添加到所谓的 vtable(虚拟方法Table) 用于该类,其中包含指向函数的指针。

    现在由于 vtable 是类的一部分,它被其子类继承,因此虚方法也被继承。现在是覆盖位。当编译器在方法声明中看到 override 时,它会查找 vtable,找到要覆盖的方法并更改函数指针以使其指向新的定义。

    因此,您既可以继承父类的方法,也可以在子类中更改它们的定义。

    有关更多信息,请参阅Virtual Method Table 上的维基百科文章。

    【讨论】:

    • 会不会是 vtable 中的方法实际上是链接而不是覆盖的?我的目标是从覆盖方法中我们可以用基调用覆盖方法。
    • 我认为链是由继承隐含的。当您调用基方法时,您实际上是在查找由基类定义的虚拟方法的定义并调用该方法。实际上,您查找基类的 vtable 并使用它。这就是为什么无论如何你都需要使用 base 来调用它,以便编译器知道在哪里查找。
    • 不,使用base.Foo() 不涉及任何进一步的 vtable 查找。为什么会这样 - 类总是知道它的基类,所以它确切地知道在编译时在基调用中调用哪个方法。
    • 所以只有在基类中声明了virtual,才不会调用继承的类覆盖,对吧?因为编译器在编译时根本不知道被继承的类存在。而“当编译器在方法声明中看到覆盖时”这一行发生在运行时,那么这怎么会发生呢?
    • 忘了上面第二个问题,我得到了@harpo的回答
    【解决方案2】:

    您无需进入 IL - virtualoverride 包含一个众所周知的面向对象概念,称为 polymorphism。实际上,当访问多态方法或属性时,实际应用的方法/属性仅在运行时确定。在引擎盖下,基本上,正确的方法(在属性的情况下,它也是一种方法)是通过访问一个虚拟方法表来确定的 - 一个用于查找正确方法的查找表,基于运行时类型。

    【讨论】:

      【解决方案3】:

      如果您对 IL 感兴趣,请使用 ildasm.exe 查看已编译的程序(DLL 或 EXE)。您会看到标记为“虚拟”的方法在 IL 中只是简单地标记为“虚拟”。

      奇迹发生在运行时。 CLR 构建一个“方法分派表”(或“虚拟方法表”),用于在内存中定位类的方法。为了允许多态性,其中相同的方法名称根据运行时类型表示不同的东西,虚拟方法需要一些额外的查找。 (人们可以说它们被称为“虚拟”方法正是因为它们是“凭借”它们所操作的内容而被选中的——但请参阅@Pavel 的 cmets。)Joe Duffy 这样说:

      虚方法调用非常多 像一个普通的电话,除了它 必须查找调用的目标 基于“this”对象的运行时。

      这些是基础。如果您真的想更进一步,Don Box 是一本不错的读物。

      【讨论】:

      • 这是virtual 的一个有趣的词源,但我会很好奇这是否是一个回顾性解释(就像 VB 的 Dim 被解释为 Declare In Memory 这些天 - 最初它来自 @ 987654326@,仅用于数组),或者真实的东西;如果是后者,你有什么参考资料吗?我知道virtual 在这个精确意义上首先出现在第一个面向对象语言 Simula-67 中。但我不记得在语言参考中看到该关键字的解释......
      • 好的,所以我要去那里了……但我觉得很安全。 Declare-in-memory 对我来说是一个新的——我只知道它是旧的数组维度关键字。无论如何,很高兴收到一位语言爱好者的来信。
      • 我相信我已经找到了。 “virtual”是“virtual quantity”的简写;他们之所以这么称呼它,是因为他们最初设想的机制主要用于属性。见books.google.com/…
      • 哇,很好的研究。坦率地说,我现在觉得这本书相当不透明,但我想我理解你的解释。这听起来有点像 Dim 扩展其声明能力以应用于更广泛的概念(其中“维度”不适用)的方式。同时,虚函数比虚属性更受追捧。 .NET 直到 2.0 版才添加虚拟属性
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-04
      • 1970-01-01
      • 1970-01-01
      • 2020-05-21
      • 2019-05-21
      • 2016-03-19
      相关资源
      最近更新 更多