Моя 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 недостаточно для того, чтобы я смог решить эту задачу самостоятельно. Возможно ли вообще определить такой определяемый пользователем тип?
@IanBush Это единственные две ошибки, которые отображает компилятор.
"процедура, приватная :: kom_bro_sab ! 16 строк" не Фортран. Что это должно быть?
@IanBush Теперь это Фортран. Я не знаю, как эта часть была вставлена туда. Возможно, эта часть попала туда во время написания вопроса.
У вас несколько ошибок. Самое главное, что перегрузка оператора неверна. См. мой пример реализации ниже.
Производный тип данных для комплексных чисел (имя файла 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
Вы можете выполнить перегрузку оператора с помощью процедуры привязки общего типа, на самом деле у меня был рабочий пример до того, как я начал полностью перестраивать Рождество из-за запоздалых заявлений Славного Лидера сегодня днем - потерял волю к жизни сейчас, опубликую завтра.
Решение отличное и открыло мне много вещей. Можете ли вы показать мне, как это делается с использованием generic, public :: operator (+)
? Можно ли создать конструктор функции с именем kom_bro
, если `bro_rea` и bro_img
с атрибутом являются закрытыми?
@IanBush Я буду очень признателен за ваш шаг, если вы завтра покажете путь через общее имя, потому что я хочу узнать, как это сделать через общее имя и как это сделать через оператор интерфейса. Можно ли создать конструктор функции с именем kom_bro, если `bro_rea` и bro_img с атрибутом являются частными?
@HarryKastorp Я добавил код в пример решения. Я надеюсь, что это ответит на ваш вопрос: «Можно ли создать конструктор функции с именем kom_bro, если ` bro_rea ` и bro_img с атрибутом являются частными?»
@HarryKastorp Вам нужно будет переименовать интерфейс конструктора. В противном случае вы не сможете различить их в выражении use mod_kompleks, only: kom_bro
. Стандартный метод в любом случае заключается в использовании подпрограммы init
с привязкой к типу.
@IanBush Я мельком видел твой ответ ночью, но теперь его нет.
@HarryKastorp Я думаю, что уместно создать новый вопрос для вопроса о видимости. нет смысла обсуждать это здесь, в комментариях (на самом деле мы должны удалить эти комментарии, поскольку они не связаны с перегрузкой операторов).
@HarryKastorp - опубликовал это, а затем удалил, так как без объяснения причин я счел это неуместным. Сегодня был слишком занят другими делами. Когда-нибудь вернемся к этому.
@HarryKastorp восстановил мой предыдущий ответ, но не в состоянии отполировать его, как я надеялся.
Вот код, который я написал, немного беспорядок, но показывает, что, как я думаю, вам нужно
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$
Ошибки, о которых вы сообщаете, — не единственные ошибки, которые компилятор найдет в приведенном выше коде — не могли бы вы опубликовать полный список ошибок или код, который вы фактически компилируете.