Как правильно определить перегрузку арифметического оператора для определяемого пользователем комплексного числа в фортране?

Моя 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 недостаточно для того, чтобы я смог решить эту задачу самостоятельно. Возможно ли вообще определить такой определяемый пользователем тип?

Ошибки, о которых вы сообщаете, — не единственные ошибки, которые компилятор найдет в приведенном выше коде — не могли бы вы опубликовать полный список ошибок или код, который вы фактически компилируете.

Ian Bush 19.12.2020 18:50

@IanBush Это единственные две ошибки, которые отображает компилятор.

Harry Kastorp 19.12.2020 19:16

"процедура, приватная :: kom_bro_sab ! 16 строк" не Фортран. Что это должно быть?

Ian Bush 19.12.2020 19:21

@IanBush Теперь это Фортран. Я не знаю, как эта часть была вставлена ​​туда. Возможно, эта часть попала туда во время написания вопроса.

Harry Kastorp 19.12.2020 19:30
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
147
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

У вас несколько ошибок. Самое главное, что перегрузка оператора неверна. См. мой пример реализации ниже.

Производный тип данных для комплексных чисел (имя файла 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 Bush 19.12.2020 22:30

Решение отличное и открыло мне много вещей. Можете ли вы показать мне, как это делается с использованием generic, public :: operator (+)? Можно ли создать конструктор функции с именем kom_bro, если `bro_rea` и bro_img с атрибутом являются закрытыми?

Harry Kastorp 19.12.2020 22:41

@IanBush Я буду очень признателен за ваш шаг, если вы завтра покажете путь через общее имя, потому что я хочу узнать, как это сделать через общее имя и как это сделать через оператор интерфейса. Можно ли создать конструктор функции с именем kom_bro, если `bro_rea` и bro_img с атрибутом являются частными?

Harry Kastorp 19.12.2020 23:17

@HarryKastorp Я добавил код в пример решения. Я надеюсь, что это ответит на ваш вопрос: «Можно ли создать конструктор функции с именем kom_bro, если ` bro_rea ` и bro_img с атрибутом являются частными?»

jack 20.12.2020 00:58

@HarryKastorp Вам нужно будет переименовать интерфейс конструктора. В противном случае вы не сможете различить их в выражении use mod_kompleks, only: kom_bro. Стандартный метод в любом случае заключается в использовании подпрограммы init с привязкой к типу.

jack 20.12.2020 15:14

@IanBush Я мельком видел твой ответ ночью, но теперь его нет.

Harry Kastorp 20.12.2020 18:29

@HarryKastorp Я думаю, что уместно создать новый вопрос для вопроса о видимости. нет смысла обсуждать это здесь, в комментариях (на самом деле мы должны удалить эти комментарии, поскольку они не связаны с перегрузкой операторов).

jack 20.12.2020 18:47

@HarryKastorp - опубликовал это, а затем удалил, так как без объяснения причин я счел это неуместным. Сегодня был слишком занят другими делами. Когда-нибудь вернемся к этому.

Ian Bush 20.12.2020 19:00

@HarryKastorp восстановил мой предыдущий ответ, но не в состоянии отполировать его, как я надеялся.

Ian Bush 06.01.2021 19:33

Вот код, который я написал, немного беспорядок, но показывает, что, как я думаю, вам нужно

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$ 

Другие вопросы по теме