Я проверил подобные вопросы и соответствующие учебники, но не могу найти решение этой проблемы.
NB: здесь используется современный Fortran.
Итак, я хочу иметь базовый тип, например. base
, который содержит процедуру с привязкой к типу, например. run
, который делегирует подпрограмме типы, расширяющие базу, например. type, extends(base) :: my_extension
. Давайте вызовем подпрограмму, которой мы хотим делегировать my_procedure
.
Я могу добиться этого довольно запутанным способом, сделав base
абстрактным, заставив base
содержать отложенную процедуру, например. delegate
, получение run
для делегирования delegate
, затем реализация delegate
в my_extension
и его делегирование my_procedure
.
Однако это беспорядочно, так как для реализации delegate
требуются типы, расширяющие base
, но все реализации просто делегируют какую-то другую процедуру. Это еще более усложняется тем фактом, что я обычно хочу несколько экземпляров my_extension
, где каждый экземпляр делегирует другую процедуру в my_extension
, и в этом случае мне нужно сохранить my_extension
абстрактным, расширить my_extension
и реализовать delegate
там, чтобы я получил столько расширений. как у меня процедуры!
Итак, мне интересно, есть ли более чистый способ использования указателей процедур или подобных. Я хочу что-то вроде этого...
база.f90:
module base_mod
implicit none
type base
procedure(my_interface), pointer :: ptr ! Pointer component
contains
procedure :: run ! Type-bound procedure
end type base
abstract interface
subroutine my_interface(self)
import :: base
class(base) :: self ! This is a problem...
end subroutine my_interface
end interface
contains
subroutine run(self)
class(base) :: self
call self%ptr()
end subroutine run
end module base_mod
мое_расширение.f90:
module my_extension_mod
use base_mod
implicit none
type, extends(base) :: my_extension
contains
procedure :: my_procedure
end type my_extension
contains
subroutine my_procedure(self)
class(my_extension) :: self ! ...because this is different.
! Do useful stuff, e.g.
print *, "my_procedure was run"
end subroutine my_procedure
end module my_extension_mod
основной.f90:
program main
use my_extension_mod
implicit none
type(my_extension) :: my_instance
procedure(my_interface), pointer :: my_ptr
my_ptr => my_procedure
my_instance = my_extension(my_ptr) ! Use implicit constructor
call my_instance%run() ! Expect to see "my_procedure was run" printed
end program main
сделать.ш:
#! /bin/bash
gfortran -c base.f90
gfortran -c my_extension.f90
gfortran base.o my_extension.o main.f90
Однако компилятор жалуется на следующее:
main.f90:9.14:
my_ptr => my_procedure
1
Error: Interface mismatch in procedure pointer assignment at (1): Type/rank mismatch in argument 'self'
Это связано с тем, что my_interface
ожидает объект класса base
в качестве входных данных, тогда как my_procedure
имеет в качестве входных данных объект класса my_extension
, поэтому технически интерфейсы не совпадают. Тем не менее, my_extension
расширяет base
, так что в некотором смысле это должно быть нормально (но очевидно, что это не так с точки зрения компилятора).
Итак, мой вопрос: как я могу решить эту проблему? Как я могу иметь интерфейс, который работает для my_procedure
, но по-прежнему работает для других процедур в других типах, которые расширяют base
(например, в my_other_extension
)? Или как я могу иметь указатели на процедуры в расширениях base
без использования интерфейса? Или как я могу достичь того, что я пытаюсь сделать другим способом (например, без использования указателей), но при этом избегая запутанного метода абстрактного типа, описанного выше?
base
, называемыеmy_extension
иmy_other_extension
. У каждого есть 2 процедуры:my_extension_procedure_one
,my_extension_procedure_two
,my_other_extension_procedure_one
иmy_other_extension_procedure_two
. Я хочу создать 4 объекта классаbase
, где указатель в 1-м объекте указывает наmy_extension_procedure_one
, указатель во 2-м объекте указывает наmy_extension_procedure_two
и т. д. Затем я могу сохранить их в массиве объектовbase
и вызватьrun
для каждого, который будет по сути, вызовите каждую из 4 процедур один раз. Это имеет больше смысла? - person Biggsy   schedule 16.05.2018ptr(1)=>type1%proc1; ptr(2)=>type1%proc2; ptr(3)=>type2%proc1; ptr(4)=>type2%proc2
) так что, возможно, этот массив меня мало спасет. - person francescalus   schedule 16.05.2018my_procedure
в расширении? Нужно ли привязывать процедуруmy_procedure
к этому типу? - person IanH   schedule 16.05.2018my_extension
должны быть привязаны к типу. Это связано с тем, что они будут вызывать другие процедуры с привязкой к типу вbase
, которые изменяют состояние компонентовbase
. Еслиmy_extension_procedure_one
и т. д. не привязаны к типу, то объектыbase
должны быть переданы, что негативно влияет на APImy_extension_procedure_one
и т. д. хуже, чем исходная проблемаmy_extension
и т. д. должна быть абстрактной. - person Biggsy   schedule 17.05.2018base
вmy_extension_procedure_one
и т. д., чтобы можно было изменить их состояние. Это создает беспорядок в API, поскольку пользователи не хотят писать процедуры, которые получают объектbase
. Я бы сказал, что в объектно-ориентированном программировании есть нечто большее, чем просто динамическая диспетчеризация — это также инкапсуляция, которую я пытаюсь здесь сделать. - person Biggsy   schedule 17.05.2018