Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 继承中的方法调用_C#_Oop_Inheritance - Fatal编程技术网

C# 继承中的方法调用

C# 继承中的方法调用,c#,oop,inheritance,C#,Oop,Inheritance,让我们假设我有一个父类和一个子类,我重载了父类方法中的一个 我正在将子类对象指定给父类引用变量。我知道,当我尝试调用父类方法时,它将调用子类方法 但这背后的原因是什么?什么是程序控制流程?堆中发生了什么?这里的神奇之处是一个查找表 当您将该方法声明为虚拟时,该方法将添加到链接到该类型的表中,并且对该方法的所有调用都将在表中查找要调用的方法的地址 因此,调用将编译为查找,然后再编译为对从表中检索的值的调用,而不是在对特定地址的特定方法的调用中编译 例如,假设基类型具有以下表: [1000] 对于

让我们假设我有一个父类和一个子类,我重载了父类方法中的一个

我正在将子类对象指定给父类引用变量。我知道,当我尝试调用父类方法时,它将调用子类方法


但这背后的原因是什么?什么是程序控制流程?堆中发生了什么?

这里的神奇之处是一个查找表

当您将该方法声明为虚拟时,该方法将添加到链接到该类型的表中,并且对该方法的所有调用都将在表中查找要调用的方法的地址

因此,调用将编译为查找,然后再编译为对从表中检索的值的调用,而不是在对特定地址的特定方法的调用中编译

例如,假设基类型具有以下表:

[1000]
对于第一种类型,所讨论的方法位于地址1000

对于第二种类型,此表如下所示:

[2000]
call method at address 1000
get address to type virtual method table (vtable)
get adress from index 0 in the table
call the method at that address
相同的重写方法现在位于地址2000

如果该方法不是虚拟的,则调用它,如以下调用:

baseObject.Method1();
将编译为如下内容:

[2000]
call method at address 1000
get address to type virtual method table (vtable)
get adress from index 0 in the table
call the method at that address
但是现在它看起来会像这样:

[2000]
call method at address 1000
get address to type virtual method table (vtable)
get adress from index 0 in the table
call the method at that address

这里的神奇之处在于一个查找表

当您将该方法声明为虚拟时,该方法将添加到链接到该类型的表中,并且对该方法的所有调用都将在表中查找要调用的方法的地址

因此,调用将编译为查找,然后再编译为对从表中检索的值的调用,而不是在对特定地址的特定方法的调用中编译

例如,假设基类型具有以下表:

[1000]
对于第一种类型,所讨论的方法位于地址1000

对于第二种类型,此表如下所示:

[2000]
call method at address 1000
get address to type virtual method table (vtable)
get adress from index 0 in the table
call the method at that address
相同的重写方法现在位于地址2000

如果该方法不是虚拟的,则调用它,如以下调用:

baseObject.Method1();
将编译为如下内容:

[2000]
call method at address 1000
get address to type virtual method table (vtable)
get adress from index 0 in the table
call the method at that address
但是现在它看起来会像这样:

[2000]
call method at address 1000
get address to type virtual method table (vtable)
get adress from index 0 in the table
call the method at that address

有两个关键因素使之成为可能:

特定类型的每个对象都有一个指向的指针,其中包含指向对该类型有效的虚拟方法实现的指针。 继承不会改变表中方法的顺序,它可以在末尾追加更多的方法,因此方法在子类中重写它并生成更多表时保持相同的索引。 在运行时,编译器知道您正在调用的方法的索引,并使用该索引在表中作为查找来实现调用

由于上面的1,无论对象在运行时恰好具有哪种类型,而不是在编译时声明的类型,都将使用包含正确方法实现的查找表。 由于上面的2,编译器使用的索引将找到正确的方法,即使运行时类型和查找表在编译时是未知的。 事实上,该机制适用于甚至还不存在的类型!方法调用可以在有人将子类型和方法实现指定给它之前很久编写和编译


免责声明:C实现的实际细节比上面描述的更复杂,例如接口需要双重查找,存在反射等,但基本思想保持不变。

有两个关键因素使之成为可能:

特定类型的每个对象都有一个指向的指针,其中包含指向对该类型有效的虚拟方法实现的指针。 继承不会改变表中方法的顺序,它可以在末尾追加更多的方法,因此方法在子类中重写它并生成更多表时保持相同的索引。 在运行时,编译器知道您正在调用的方法的索引,并使用该索引在表中作为查找来实现调用

由于上面的1,无论对象在运行时恰好具有哪种类型,而不是在编译时声明的类型,都将使用包含正确方法实现的查找表。 由于上面的2,编译器使用的索引将找到正确的方法,即使运行时类型和查找表在编译时是未知的。 事实上,该机制适用于甚至还不存在的类型!方法调用可以在有人将子类型和方法实现指定给它之前很久编写和编译


免责声明:C实现的实际细节比上面描述的更复杂,例如接口需要双重查找,存在反射等,但基本思想保持不变。

您能详细解释吗