当我们从具有传递过程指针的数据类型(类)创建多个实例时,是否在每个实例中复制了实际过程(子例程/函数)?或只是复制指针?
例如,请考虑以下编译和运行正确的代码 .
module mod2
implicit none
private
type class_type
integer :: a, b, c
contains
procedure :: add => add_it
end type class_type
public :: class_type
contains
subroutine add_it(this)
implicit none
class(class_type), intent(inout) :: this
this%c = this%a + this%b
end subroutine add_it
end module mod2
program tester
use mod2
implicit none
type(class_type), dimension(10) :: objs
objs(:) = class_type(1, 2, 0)
end program tester
从数据类型 class_type
创建的10个对象中的每个对象中是否重复了子程序 add_it
?或者是子程序 add_it
的指令集存储在某处并指向它,即 "procedure :: add => add_it"
复制在每个对象中?
1 回答
通常都没有 . 请注意,这是非常具体的实现 - 我在下面描述的是典型的,但不同的处理器可能会做不同的事情 .
请注意,示例中没有过程指针 .
class_type
类型具有绑定 . 如果class_type
有一个过程指针,则情况就不同了 .绑定的典型实现是编译器创建一个机器级指针表,每个特定绑定有一个条目,指针指向过程的代码 . 为程序中的每种类型创建一个表(有时称为“vtable”,来自用于C和类似语言中的虚拟成员函数的类似技术) .
对于 polymorphic 对象(用
CLASS
声明的事物),编译器然后创建一个描述符,该描述符具有指向对象的动态(运行时)类型的相关表的机器级指针 . 该指针有效地指示对象的动态类型,并且可以在诸如SELECT TYPE
之类的构造中使用,并且可以在诸如SAME_TYPE_AS
之类的东西中进行调用 . 如果你有一个多态数组,编译器最初通常只为整个数组创建一个描述符,因为数组中的各个元素必须都具有相同的动态类型 .当您对多态对象调用绑定时,编译器将跟随指向vtable的指针,然后查找指向过程绑定的相关指针 .
非多态对象(使用TYPE声明的事物)不需要这样的描述符或指针解引用,因为动态和声明的类型总是相同的,编译器知道声明的类型是什么,并且编译器在编译时知道哪个过程将叫做 .
如果您有一个过程调用,其中非多态实际参数与多态伪参数相关联,那么编译器通常会创建必要的描述符作为进行过程调用的一部分 . 类似地,将多态数组元素传递给采用多态标量的过程 .
您的代码的主程序不包含多态实体,并且您不调用任何过程,因此可能没有任何机器指针返回到vtable .
过程指针组件(在类型声明的CONTAINS之前声明为
PROCEDURE(xxx), POINTER :: yyy
的组件)对于每个对象可以是不同的(包括对于数组中的每个元素都不同) . 在这种情况下,典型的实现是将机器级指针存储到相关过程的代码(如果过程指针组件尚未关联,则为空指针) .