如何在 Fortran 中为用户定义的复数正确定义算术运算符重载?

How to define correctly arithmetic operator overloading for user defined complex number in fortran?

我的 IDE 是:Code::Blocks 20.03 (MinGW 9.2.0)

这是我的简单代码:

module mod_kompleks

  use, intrinsic :: iso_c_binding, only : rp => c_double

  implicit none

  type, public :: kom_bro

    private

    real(rp) :: dio_rea
    real(rp) :: dio_img

    contains

      procedure, private :: kom_bro_sab    ! 16 line

      generic, public :: operator(+) => kom_bro_sab  ! 18 line

  end type kom_bro

  interface kom_bro

    module procedure :: kom_bro_set

  end interface kom_bro

  contains

  ! procedure - kom_bro_set

    type(kom_bro) function kom_bro_set(rea_part, img_part) result(bro_c)

      real, intent(in) :: rea_part, img_part

      bro_c%dio_rea = rea_part
      bro_c%dio_img = img_part

    end function kom_bro_set

  ! procedure - kom_bro_sab

    function kom_bro_sab(bro_a, bro_b) result(bro_c)

      type(kom_bro), intent(in) :: bro_a
      type(kom_bro), intent(in) :: bro_b
      type(kom_bro)             :: bro_c

      bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
      bro_c%dio_img = bro_a%dio_img + bro_b%dio_img

    end function kom_bro_sab

end module mod_kompleks

program kompleksni_broj

  use, non_intrinsic :: mod_kompleks

  implicit none

  integer :: i

  type(kom_bro) :: broj_01(3)
  type(kom_bro) :: broj_02(3)
  type(kom_bro) :: broj_03(3)

  do i = 1, 3

    broj_01(i) = kom_bro(i + 2.2,i + 3.3)
    broj_02(i) = kom_bro(i + 4.4,i + 5.5)

    broj_03(i) = broj_01(i) + broj_02(i)

  end do

end program kompleksni_broj

我打算定义一个看起来像复数但也允许将两个复数相加的算术运算的用户类型。由于我在示例中没有使用 Fortran 编程语言的经验,因此我遇到了编译器向我报告以下错误的问题:

|16|Error: Non-polymorphic passed-object dummy argument of 'kom_bro_sab' |18|Error: Undefined specific binding 'kom_bro_sab' as target of GENERIC '+' ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

我对编程语言 Fortran 中的 OOP 的了解不足以让我自己解决这个问题。 甚至可以定义这样的用户定义类型吗?

您有多个错误。最重要的是运算符重载是错误的。请参阅下面我的示例实现。

复数的派生数据类型(文件名b.f90

module mod_kompleks
  use, intrinsic :: iso_c_binding, only : rp => c_double
  implicit none

  private
  public kom_bro
  public operator(+)

  type kom_bro
    private
    real(rp) :: dio_rea
    real(rp) :: dio_img
  contains
    procedure :: init  => kom_bro_init
    procedure :: print => kom_bro_print
  end type

  interface operator(+)
    module procedure kom_bro_sab
  end interface

  interface kom_bro
    module procedure kom_bro_init2
  end interface
contains
  function kom_bro_init2(rea_part, img_part) result(bro)
    real(rp), intent(in) :: rea_part
    real(rp), intent(in) :: img_part
    type(kom_bro)        :: bro

    call bro%init(rea_part, img_part)
  end function

  subroutine kom_bro_init(this, rea_part, img_part)
    class(kom_bro), intent(out) :: this
    real(rp),       intent(in)  :: rea_part
    real(rp),       intent(in)  :: img_part

    this%dio_rea = rea_part
    this%dio_img = img_part
  end subroutine

  subroutine kom_bro_print(this)
    class(kom_bro), intent(in) :: this

    print *, this%dio_rea, this%dio_img
  end subroutine

  function kom_bro_sab(bro_a, bro_b) result(bro_c)
    type(kom_bro), intent(in) :: bro_a
    type(kom_bro), intent(in) :: bro_b
    type(kom_bro)             :: bro_c

    bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
    bro_c%dio_img = bro_a%dio_img + bro_b%dio_img
  end function
end module

程序(文件名a.f90

program kompleksni_broj
  use mod_kompleks
  use, intrinsic :: iso_c_binding, only : rp => c_double

  implicit none

  integer       :: i
  type(kom_bro) :: broj_01(3), broj_02(3), broj_03(3)

  do i = 1, 3
    call broj_01(i)%init(i + 2.2_rp, i + 3.3_rp)      ! initialization via type-bound routine
    broj_02(i) = kom_bro(i + 4.4_rp, i + 5.5_rp)      ! initialization via interface kom_bro aka "type constructor"

    broj_03(i) = broj_01(i) + broj_02(i)
    call broj_03(i)%print()
  end do

end program

输出

$ gfortran -g3 -Wall -fcheck=all b.f90 a.f90 && ./a.out
   3.2000000000000002        5.4000000000000004        8.6000000000000014     
   4.2000000000000002        6.4000000000000004        10.600000000000001     
   5.2000000000000002        7.4000000000000004        12.600000000000001

这是我写的代码,有点乱,但显示了我认为你想要的东西

ian@eris:~/work/stack$ gfortran --version
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ cat poly.f90
module mod_kompleks

  use, intrinsic :: iso_c_binding, only : rp => c_double

  implicit none

  type, public :: kom_bro

    private

    real(rp) :: dio_rea
    real(rp) :: dio_img

    contains

      Procedure, private :: kom_bro_sab    ! 16 line
      Procedure, Public  :: print => kom_bro_print
      Procedure, Public  :: set   => kom_bro_set

      generic, public :: operator(+) => kom_bro_sab  ! 18 line

  end type kom_bro

!!$  interface kom_bro
!!$
!!$    module procedure :: kom_bro_set
!!$
!!$  end interface kom_bro

  Private

contains

  ! procedure - kom_bro_set

!!$    type(kom_bro) function kom_bro_set(rea_part, img_part) result(bro_c)
    Subroutine kom_bro_set( bro_c, rea_part, img_part)

      Class( kom_bro ), Intent( InOut ) :: bro_c

      real, intent(in) :: rea_part, img_part

      bro_c%dio_rea = rea_part
      bro_c%dio_img = img_part

!!$    end function kom_bro_set
    end Subroutine kom_bro_set

  ! procedure - kom_bro_sab

    function kom_bro_sab(bro_a, bro_b) result(bro_c)

      Class(kom_bro), intent(in) :: bro_a
      Class(kom_bro), intent(in) :: bro_b
      Class(kom_bro), Allocatable :: bro_c

      ! Allocate the return value to the same type as
      ! one of the provided arguments - may have to modify this depending
      ! on requirements
      Allocate( bro_c, Mold = bro_a )
      
      bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
      bro_c%dio_img = bro_a%dio_img + bro_b%dio_img

    end function kom_bro_sab

    Subroutine kom_bro_print( bro_a )

      Class( kom_bro ), Intent( In ) :: bro_a

      Write( *, * ) 'Real: ', bro_a%dio_rea, ' Imag: ', bro_a%dio_img
      
    End Subroutine kom_bro_print

end module mod_kompleks

program kompleksni_broj

  use, non_intrinsic :: mod_kompleks

  implicit none

  integer :: i

  type(kom_bro) :: broj_01(5)
  type(kom_bro) :: broj_02(5)
  type(kom_bro) :: broj_03(5)

  do i = 1, 5

!!$    broj_01(i) = kom_bro(i + 2.2,i + 3.3)
!!$    broj_02(i) = kom_bro(i + 4.4,i + 5.5)
     Call broj_01(i)%set(i + 2.2,i + 3.3)
     Call broj_02(i)%set(i + 4.4,i + 5.5)
     
    broj_03(i) = broj_01(i) + broj_02(i)

    Write( *, * ) i
    Call broj_01(i)%print
    Write( *, * ) i
    Call broj_02(i)%print
    Write( *, * ) i
    Call broj_03(i)%print

    Write( *, * )
    
  end do

end program kompleksni_broj
ian@eris:~/work/stack$ gfortran -std=f2008 -Wall -Wextra -fcheck=all poly.f90 
ian@eris:~/work/stack$ ./a.out
           1
 Real:    3.2000000476837158       Imag:    4.3000001907348633     
           1
 Real:    5.4000000953674316       Imag:    6.5000000000000000     
           1
 Real:    8.6000001430511475       Imag:    10.800000190734863     

           2
 Real:    4.1999998092651367       Imag:    5.3000001907348633     
           2
 Real:    6.4000000953674316       Imag:    7.5000000000000000     
           2
 Real:    10.599999904632568       Imag:    12.800000190734863     

           3
 Real:    5.1999998092651367       Imag:    6.3000001907348633     
           3
 Real:    7.4000000953674316       Imag:    8.5000000000000000     
           3
 Real:    12.599999904632568       Imag:    14.800000190734863     

           4
 Real:    6.1999998092651367       Imag:    7.3000001907348633     
           4
 Real:    8.3999996185302734       Imag:    9.5000000000000000     
           4
 Real:    14.599999427795410       Imag:    16.800000190734863     

           5
 Real:    7.1999998092651367       Imag:    8.3000001907348633     
           5
 Real:    9.3999996185302734       Imag:    10.500000000000000     
           5
 Real:    16.599999427795410       Imag:    18.800000190734863     

ian@eris:~/work/stack$