Как разработать процедуру PRIVATE OVERRIDABLE в абстрактном производном типе?

Как правило, абстрактный тип является моделью для производных типов-потомков. Процедуры, содержащиеся в этом типе, должны быть ОБЩЕСТВЕННЫМИ, если они отложены, потому что на PRIVATE нельзя ссылаться или переопределять из самого модуля. Но как я могу спроектировать АБСТРАКТНЫЙ производный тип, если я хочу, чтобы каждый из потомков имел одну и ту же функциональную процедуру PRIVATE для выполнения каких-либо действий (например, для проверки статуса инициализации его экземпляра)? Должен ли я вручную определять их в каждом потомке или я могу поместить модель в РЕФЕРАТ и реализовать ее в потомке? Вот пример:

module test1
    implicit none

    private
    public :: my_numeric_type

    type, abstract :: my_numeric_type
    contains
        private
        procedure(op2), deferred :: add
        procedure(op2), deferred :: subtract
        generic, public :: operator(+) => add
        generic, public :: operator(-) => subtract
    end type my_numeric_type

    abstract interface
        function op2(a, b) result(r)
            import :: my_numeric_type
            class(my_numeric_type), intent(in) :: a, b
            class(my_numeric_type), allocatable :: r
        end function op2
    end interface
end module test1

module test2
    use test1, only: my_numeric_type
    implicit none

    type, extends(my_numeric_type) :: my_integer
        private
        integer :: value
    contains
    private
        procedure, public :: add => add_my_integer
        procedure, public :: subtract => subtract_my_integer
    end type my_integer

    contains

    function add_my_integer(a, b) result(r)
        class(my_integer),      intent(in)  :: a
        class(my_numeric_type), intent(in)  :: b
        class(my_numeric_type), allocatable :: r
        ! DO SOME ADDITION.
    end function add_my_integer

    function subtract_my_integer(a, b) result(r)
        class(my_integer),      intent(in)  :: a
        class(my_numeric_type), intent(in)  :: b
        class(my_numeric_type), allocatable :: r
        ! DO SOME SUBTRACTION.
    end function subtract_my_integer

end module test2

В примере производный тип-потомок my_integer не является абстрактным типом и наследует отложенную привязку, поэтому процедуры (сложение и вычитание) должны быть переопределены. Но процедуры определены как закрытые в my_numeric_type, то есть их нельзя переопределить вне модуля test1, поэтому указанный выше тип my_integer недействителен. Что я должен делать ?


person Blane John    schedule 29.12.2017    source источник
comment
Ветка обновлена. Большое спасибо, @Vladimir.   -  person Blane John    schedule 29.12.2017
comment
Я думаю, что это имеет много общего с stackoverflow.com/questions/47959048/ Может ли это быть дубликат?   -  person Vladimir F    schedule 29.12.2017
comment
@VladimirF, я не вижу связи между этим вопросом и тем.   -  person francescalus    schedule 29.12.2017
comment
@Vladimir, в предложенной вами ветке процедуры с привязкой к типу в обоих производных типах определены с доступом по умолчанию, который является ОБЩЕСТВЕННЫМ. Но проблема заключается в том, чтобы реализовать ЧАСТНУЮ отложенную процедуру с привязкой к типу.   -  person Blane John    schedule 30.12.2017


Ответы (1)


Из проекта стандарта fortran 2018, раздел 7.5.5, пункт 9:

Общедоступная процедура с привязкой к типу доступна через любой доступный объект типа. Приватная процедура с привязкой к типу доступна только в модуле, содержащем определение типа, и в его потомках.

Это означает, что можно реализовать private deferred процедур, но только если реализованная процедура объявлена ​​в том же модуле, что и отложенная процедура.

Например:

module m
  implicit none
  
  type, abstract :: Parent
  contains
    procedure(add_Parent), deferred, private :: add
    generic, public :: operator(+) => add
  end type
  
  abstract interface
    function add_Parent(lhs,rhs) result(output)
      import :: Parent
      class(Parent), intent(in)  :: lhs
      class(Parent), intent(in)  :: rhs
      class(Parent), allocatable :: output
    end function
  end interface
  
  type, extends(Parent) :: Child
    integer :: contents
  contains
    procedure, private :: add => add_Child
  end type
  
contains

function add_Child(lhs,rhs) result(output)
  class(Child),  intent(in)  :: lhs
  class(Parent), intent(in)  :: rhs
  class(Parent), allocatable :: output
  
  select type(rhs); type is(Child)
    output = Child(lhs%contents+rhs%contents)
  end select
end function

end module

program p
  use m
  
  type(Child)                :: a,b
  class(Parent), allocatable :: c
  
  a = Child(3)
  b = Child(5)
  c = a+b
  
  select type(c); type is(Child)
    write(*,*) c%contents
  end select
end program

Это ограничение (то, что и Parent, и Child должны быть объявлены в одном и том же модуле) может привести к большим файлам и вызвать проблемы с упорядочением зависимостей. Есть несколько способов улучшить ситуацию:

  • Используйте submodules, чтобы разбить модуль. например Parent может иметь свой собственный подмодуль, и каждый Child может иметь свой собственный подмодуль.
  • Вместо использования отложенных процедур private используйте соглашение об именах для отложенных процедур, которые следует рассматривать как частные, например конечные символы подчеркивания (такие как add_Parent_ и add_Child_).
person veryreverie    schedule 25.03.2021