考虑以下代码
module classes
Type AData
end Type
Type A
contains
procedure :: Work
end type
Type, extends(AData) :: BData
end Type
Type, extends(A) :: B
contains
procedure :: Work => Work2
end type
contains
subroutine Work(this, D)
class(A) :: this
class(*) :: D
end subroutine
subroutine Work2(this, D)
class(B) :: this
class(BData) :: D
end subroutine
end module classes
这有效吗?它被ifort接受并被gfortran拒绝(因为Work2的第二个参数中的类不相同)。
如果它无效,在某些情况下似乎显然是有用的:使用不同类型的更多参数,后代过程必须有多个嵌套的“select type”语句才能将参数转换为期望的类型。如果在编译时知道参数将在后代类中具有哪些类型(以丢失一些编译时一致性检查为代价),这将是非常冗长的并且可能也是效率较低的。是否有编译器选项使gfortran接受此构造,或者它应该是gcc错误报告/功能请求吗?
- Edit--: 明确一点,Gfortran 4.9 trunk给出了 错误:在(1)处覆盖过程'work'的参数不匹配:参数'd'中的类型不匹配(CLASS(bdata)/ CLASS(*))
ifort(但不是gfortran)也允许构造如
subroutine Work2(this, D)
class(B) :: this
class(*), target :: D
class(BData), pointer :: B
B=>D
end subroutine
因此似乎将类(星)变量视为具有“信任我,我知道它是什么类型”标签来自开发人员。对我来说,这似乎是非常合理的(如果谨慎使用),并避免选择类型操作的开销,有时甚至是非常长的多个嵌套选择类型语句。我知道进行盲式类型转换的唯一有效方法是通过外部子例程来推送事物,其中根本没有对参数进行类型检查(可怕的方式在f90中绕过传递的aribitrary类型参数)。
使用其他类型覆盖类(星型)过程的愿望也出现在基本上下文中,例如要传递函数和任意对象的最小化库。这里开发人员和特定的函数实现总是知道对象是什么类型,即使最小化器没有,因此你不希望在使用类(*)参数的函数实现中做一个“选择类型”
答案 0 :(得分:3)
B
中的类型绑定过程会覆盖A
中的类型绑定过程,而Fortran 2008标准的4.5.7.3节中有
超越和重写的类型约束程序应满足以下条件。
...
按位置对应的虚拟参数应具有相同的名称和特征,但传递对象伪参数的类型除外。
我对此的解读是D
必须是两个子程序中的相同类型。所以,最小的变化确实会在select type
中有一个work2
构造(可能在两个子程序中都有class(Adata)
作为声明)。
但是,以下是否可行?
module classes
Type AData
end Type AData
Type A
contains
procedure :: work_adata
generic :: Work => work_adata
end type A
Type, extends(AData) :: BData
end Type BData
Type, extends(A) :: B
contains
procedure :: work_bdata
generic :: work => work_bdata
end type B
contains
subroutine Work_adata(this, D)
class(A) :: this
type(Adata) :: D
end subroutine Work_adata
subroutine Work_bdata(this, D)
class(B) :: this
type(BData) :: D
end subroutine Work_bdata
end module classes
通过使用虚拟对象的类型声明来解决数据类的多态性造成的困难。