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

Като цяло абстрактният тип е модел за потомствени производни типове. Процедурите, съдържащи се в типа, трябва да бъдат ПУБЛИЧНИ, ако е отложен, тъй като частната не може да бъде препратена или заменена извън самия модул. Но как мога да проектирам производния тип ABSTRACT, ако искам всеки един от наследниците да има една и съща функционална ЧАСТНА процедура, за да направи нещо (напр. Да тества състоянието на инициализация на своя екземпляр)? Трябва ли ръчно да ги дефинирам във всеки потомък или мога да поставя модел в АБСТРАКТ и да го внедря в потомъка? Ето един пример:

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, В нишката, която предлагате, обвързаните с тип процедури и в двата производни типа са дефинирани с достъп по подразбиране, който е PUBLIC. Но проблемът, който имам, е да внедря PRIVATE отложена обвързана с тип процедура.   -  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