C# C语言中的动态调度模板方法#
我不明白为什么要打印以下输出 静态类型是Base,调用print()并导致控制台输出:C# C语言中的动态调度模板方法#,c#,dispatch,C#,Dispatch,我不明白为什么要打印以下输出 静态类型是Base,调用print()并导致控制台输出: 第1.A款 基地B 静态类型为Sub,调用print(),并导致控制台输出: 第1.A款 基地B 为什么这里叫Base.B而不是Sub.B 静态类型为Sub,对B()的调用导致控制台输出: 第1.B款 Sub上的隐藏函数B()在程序中被调用。但如果我用print()调用它,则不会 不同之处在于从每个位置调用每个方法的方式,归结起来就是new和virtual/override之间的差异 首先是理论,
- 第1.A款
- 基地B
- 第1.A款
- 基地B
- 第1.B款
不同之处在于从每个位置调用每个方法的方式,归结起来就是
new
和virtual
/override
之间的差异
首先是理论,对这两个关键词的解释过于简单:
只是在派生类中定义了另一个方法,该方法与基类中的现有方法同名“隐藏”它。根据用于调用方法的引用类型,在编译时选择调用什么方法(base或derived)new
表示方法可以在派生类中具有替代实现,在这种情况下应该使用它。此处,根据实际对象的类型在运行时进行选择virtual
A
的所有调用都完全相同,因为它是虚拟的,并且唯一的实例是Sub
类型。动态分派完成了它的任务,这将导致调用Sub.B
,正如您所发现的那样
但是对B
的调用在两个地方。print
方法中的一个和直接在main
上的另一个。由于B
不是virtual
,它使用静态调度和编译时类型的引用来确定调用站点。来自main
的一个很容易理解为什么它使用Sub.B
。但是,print
方法中的另一个方法不使用相同的引用,它们隐式地使用this
指针调用同一类中的实例方法。这完全等同于这样写:
public void print()
{
this.A();
this.B();
}
因此,对B
的调用完全取决于this
的编译时类型,即本例中的Base
(正如在该类中编写的那样)。因此这里调用了Base.B
前面对
print
的调用来自另一种类型的变量,这一事实在这里是不相关的,因为这只用于确定要执行的print
实现(这里我们只有一个),但是该方法本身所做的任何操作都超出了这一范围,因此不会影响其行为。new关键字仅隐藏现有方法,而不会替换它。当您在基类中调用print
时,基类不知道Sub
上有另一个隐藏B
的方法,它调用B
它知道存在。但是使用virtual关键字它必须在虚拟调用表中查找Sub.A?然后,在运行时构造期间初始化该表?规范的10.6.3中有这样一句话:“在虚拟方法调用中,发生该调用的实例的运行时类型决定了要调用的实际方法实现”。我实际上不知道这背后的实现细节,但是规范中关于虚拟方法的部分(Visual Studio附带的版本中的10.6.3)似乎有很多您可能要查找的信息。根据这一点:在非虚拟方法调用中,实例的编译时类型是决定因素。感谢您对规范的提示:-)
public void print()
{
this.A();
this.B();
}