首页 文章

了解Fortran扩展了类型和覆盖

提问于
浏览
14

我试图理解Fortran 2003标准(或更高版本)中面向对象的概念 . 我对C有一些了解,所以我认为这两种语言之间有一些共同点,可以帮助我更好地理解它们 .

在C中,多态性是通过类派生和成员函数覆盖来完成的 . 一个定义了一个“抽象”基类,几乎所有的虚函数都被定义了 . 不同的派生类包含它们的实际实现 . 所以其他函数只需要基于“抽象”类进行编程 . 然后它们适用于所有派生类 .

我认为在Fortran中,OOP以类似的方式完成,但存在一些差异 . 在我看来,需要定义一个带有一些虚函数的基类型,就像C一样 . 其他函数/子例程应遵循基类型中的成员函数定义 . 这是解决所有扩展类型的函数/子例程重用的方法 .

我对如何编写这个想法没有更好的想法 . 这是我的第一次尝试:

type Basis
    integer                                 :: NBasis
contains
    private
    procedure                               :: DoNothing
    generic, public                         :: Constructor => DoNothing
    generic, public                         :: AllocateBasis => DoNothing
endtype Basis

type, extends(Basis) :: GridBasis
    private
    integer                                 :: NGrid
contains
    private
    procedure                               :: ConstructorGrid1
    procedure                               :: ConstructorGrid2
    generic, public                         :: Constructor => ConstructorGrid1, ConstructorGrid2, ConstructorGrid3
    procedure                               :: AllocateGridReal
    procedure                               :: AllocateGridCplx
    generic, public                         :: AllocateBasis => AllocateGridReal, AllocateGridCplx
endtype GridBasis
  • 首先,如何在类型Basis中定义“AllocateBasis”,使其像“虚函数”一样工作,所有扩展类型必须定义自己的“AllocateBasis”版本?

  • 其次,如何在GridBasis类型中定义“AllocateBasis”?这里的定义包含它的真实实现 .

  • 第三,如何在GridBasis类型中使“AllocateBasis”成为重载函数?即存在真实版本和复杂版本,并且它们都被命名为“AllocateBasis”,具有实际或复杂的输入可分配数组 .

  • 第四,NOPASS与PASS . 据我所知,如果设置了PASS,那么就会有一个指向该对象的显式指针 . 但是当NOPASS设定时,就没有这样的东西了 . 那么PASS是简化澄清的吗?

1 回答

  • 17

    首先是您的问题的一些评论/答案:

    • 您可以声明类型绑定过程为 deferred . 然后,您必须在没有特定实现的情况下定义其签名(接口) . 必须将包含 deferred 过程的类型声明为 abstract . 这些类型无法实例化 . 所有扩展类型必须为给定的过程提供实现,除非它们本身是 abstract .

    • 为了在扩展类型中为 deferred 过程提供实现,您只需在扩展类型中声明过程并为其提供实现 .

    • 您无法将给定类型的公共过程转换为扩展类型的 generic . 但是,您可以在基本类型中定义 generic 并在其派生类型中对其进行扩展 .

    • pass 属性默认设置,因此过程的第一个参数将是类型实例 . 但是,您可以指定它以使其更明确 . 此外,您可以使用 PASS(ARGNAME) 形式指定,哪个参数( ARGNAME )应该是实例 . 这个论点不一定是程序中的第一个 .

    下面是一个包含自我的示例,其中应包含您要求的所有功能:

    module basis_module
      implicit none
    
      type, abstract :: Basis
        integer :: NBasis
      contains
        procedure(allocBasisR1Interface), deferred :: allocateBasisR1
        generic :: allocateBasis => allocateBasisR1
      end type Basis
    
      interface 
        ! Interface for real basis allocation
        subroutine allocBasisR1Interface(self, array)
          import
          class(Basis), intent(inout) :: self
          real, intent(in) :: array(:)
        end subroutine allocBasisR1Interface
      end interface
    
    end module basis_module
    
    
    module extension_module
      use basis_module
      implicit none
    
      type, extends(Basis) :: GridBasis
      contains
        ! Extending the mapping allocateBasis => allocateBasisR1 of
        ! the parent type.
        generic :: allocateBasis => allocateBasisC1
        procedure :: allocateBasisC1
        ! Implementation for the deferred procedure in Basis
        procedure :: allocateBasisR1
      end type GridBasis
    
    contains
    
      subroutine allocateBasisR1(self, array)
        class(GridBasis), intent(inout) :: self
        real, intent(in) :: array(:)
    
        self%NBasis = size(array)
        print *, "GridBasis:allocateBasisR1"
    
      end subroutine allocateBasisR1
    
    
      subroutine allocateBasisC1(self, array)
        class(GridBasis), intent(inout) :: self
        complex, intent(in) :: array(:)
    
        self%NBasis = size(array)
        print *, "GridBasis:allocateBasisC1"
    
      end subroutine allocateBasisC1
    
    end module extension_module
    
    
    program test
      use extension_module
      implicit none
    
      type(GridBasis) :: mybasis
      real :: myRealArray(10)
      complex :: myComplexArray(5)
    
      call mybasis%allocateBasis(myRealArray)
      call mybasis%allocateBasis(myComplexArray)
    
    end program test
    

相关问题