gpt4 book ai didi

oop - 在 Fortran 中扩展对象并覆盖过程而不延迟

转载 作者:行者123 更新时间:2023-12-03 03:35:52 25 4
gpt4 key购买 nike

我有一个包含许多不同功能和方法的代码。有些方法都是针对同一个特征,即只能选择一个选项。

此外,根据功能,我可能需要在其他地方修改子例程。因此,在例程 inject 的循环中,我可能有一个小的 if 语句,询问我是否使用了功能 A,然后执行一些额外的操作。这是非常令人沮丧的,因为不同的功能似乎与其他例程非常任意地连接,并且可能难以维护。

我决定采取以下措施来避免这种情况:

我定义了一个对象t_inject,其目的是执行例程inject。我重写了例程inject,使其仅包含所有不同场景通用的代码。

 type t_inject 


contains

procedure,nopass :: inject => inject_default
end type

现在我有另一个对象来处理我的功能A,以防它被选中。

 type,extends(t_inject) :: t_inject_a


contains

procedure, nopass :: inject => inject_a
end type

我的子例程inject_a和inject具有相同的接口(interface)。例如

 subroutine inject_a( part ) 
type(t_part) , intent(inout) :: part % an external data type
call inject(part)
! do the extra bit of stuff you need to do

end subroutine

subroutine inject( part)
type(t_part) , intent(inout) :: part % an external data type

! carry out the default stuff
end subroutine

现在在我的主程序中

class(t_inject) :: inj 

allocate(inj :: t_inject_a)

call inj% inject ( part)

您会这样做吗?它有效吗?
我最初考虑使用延迟注入(inject)过程来创建一个抽象声明类型,然后我可以在其中进行扩展。但对于一个非常微不足道的问题,我可能不需要 - 我还想知道我的调用 call inj%ject(part) 是否足以让编译器知道要去哪里。有时我会看到代码在调用之前需要 class is 条件。

最佳答案

我认为应该修改三点:

  • 类型绑定(bind)过程需要引用实际的过程名称(通过 =>)。因此,我将模块过程 inject() 的名称更改为 inject_default()。 (但也请参阅 test2.f90)。
  • 我们需要将 allocatable 附加到类变量(例如 inj2),以使用具体类型(例如 t_inject_a)分配它.
  • allocate 语句中,具体类型的名称应出现在 :: 之前,例如 allocate( t_inject_a::inj2 ) .

修改后的代码可能如下所示:

!! test.f90
module test_mod
implicit none

type t_inject
contains
procedure, nopass :: inject => inject_default
endtype

type, extends(t_inject) :: t_inject_a
contains
procedure, nopass :: inject => inject_a
endtype

type t_part !! some other type
integer :: x = 100, y = 200
endtype

contains
subroutine inject_default( part )
type(t_part), intent(inout) :: part

print *, "x = ", part % x
endsubroutine

subroutine inject_a( part )
type(t_part), intent(inout) :: part

call inject_default( part )
print *, "y = ", part % y
endsubroutine
end

program main
use test_mod
implicit none
class( t_inject ), allocatable :: inj1, inj2
type( t_part ) :: part

!! Polymorphic allocation with concrete types.
allocate( t_inject :: inj1 )
allocate( t_inject_a :: inj2 )

print *, "inj1:"
call inj1 % inject( part )

print *, "inj2:"
call inj2 % inject( part )
end

“gfortran-8 test.90 && ./a.out”给出

 inj1:
x = 100
inj2:
x = 100
y = 200
<小时/>

我们还可以通过使用 procedure, nopass::inject 来使用模块过程 inject()(而不是 inject_default()),例如:

!! test2.f90
module test_mod
implicit none

type t_inject
contains
procedure, nopass :: inject
! procedure, nopass :: inject => inject !! this also works
endtype

type, extends(t_inject) :: t_inject_a
contains
procedure, nopass :: inject => inject_a
endtype

type t_part !! some other type
integer :: x = 100, y = 200
endtype

contains
subroutine inject( part )
type(t_part), intent(inout) :: part

print *, "x = ", part % x
endsubroutine

subroutine inject_a( part )
type(t_part), intent(inout) :: part

call inject( part )
print *, "y = ", part % y
endsubroutine
end

!! The remaining part (and the result) is the same...
<小时/>

此外,还可以将诸如 inject() 之类的实际过程分离到不同的文件中,并使用它们来定义新类型,例如 t_inject (请参阅下面的 mylib.f90test3.f90)。这对于重用某些库文件中的例程可能很有用。

!! mylib.f90
module mylib
implicit none

type t_part !! some other type
integer :: x = 100, y = 200
endtype

contains

subroutine inject( part )
type(t_part), intent(inout) :: part

print *, "x = ", part % x
end
subroutine inject_a( part )
type(t_part), intent(inout) :: part

call inject( part )
print *, "y = ", part % y
end
end

!! test3.f90
module test_mod
use mylib
implicit none

type t_inject
contains
procedure, nopass :: inject
endtype

type, extends(t_inject) :: t_inject_a
contains
procedure, nopass :: inject => inject_a
endtype
end

!! The main program is the same as test.f90.
!! compile: gfortran-8 mylib.f90 test3.f90

关于oop - 在 Fortran 中扩展对象并覆盖过程而不延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57608426/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com