Как перегрузить процедуру, объявленную в абстрактном типе в Фортране?

В следующем модуле объявляется абстрактный тип (Base_Arrays_class) и создаются два типа (One_Array_t и Two_Arrays_t). В абстрактном типе есть процедура abstract_init, отложенная на init.

В производных типах подпрограммы one_array_init и two_arrays_init используются для инициализации массива(ов).

module my_mod
    implicit none

    type, abstract :: Base_Arrays_class
        integer :: array_size
        real,dimension(:), allocatable :: array
    contains
        procedure(abstract_init), deferred :: init
    end type  Base_Arrays_class

    abstract interface
        subroutine abstract_init(this,array_size)
            import Base_Arrays_class
            class(Base_Arrays_class), intent(inout) :: this
            integer, intent(in) :: array_size
        end subroutine abstract_init
    end interface

    type, extends(Base_Arrays_class) :: One_Array_t
    contains
        procedure :: init => one_array_init
    end type One_Array_t

    type, extends(Base_Arrays_class) :: Two_Arrays_t
        real,dimension(:), allocatable :: second_array
    contains
        procedure :: init => two_arrays_init
    end type Two_Arrays_t

contains

    subroutine one_array_init(this,array_size)
        class(One_Array_t), intent(inout) :: this
        integer, intent(in) :: array_size
        
        this%array_size=array_size
        allocate(this%array(array_size))
        this%array=1.0
    end subroutine one_array_init
    
    subroutine two_arrays_init(this,array_size)
        class(Two_Arrays_t), intent(inout) :: this
        integer, intent(in) :: array_size
        
        this%array_size=array_size
        allocate(this%array(array_size), this%second_array(array_size))
        this%array=2.0
        this%second_array=3.0
    end subroutine two_arrays_init

end module my_mod

Ниже приведен пример программы, использующей этот модуль.

program pgm
    use my_mod
    implicit none
    
    type(One_Array_t) :: one_array
    type(Two_Arrays_t) :: two_arrays
    integer :: i, size
    
    size = 4    
    call one_array%init(size)
    call two_arrays%init(size)
    
    print *,"one_array"
    do i=1,size
        print *, one_array%array(:)
    end do
    
    print *,"two_arrays"
    do i=1,size
        print *, two_arrays%array(:)
    end do
    print *
    do i=1,size
        print *, two_arrays%second_array(:)
    end do

end program pgm

Он работает отлично.

Но теперь я хотел бы перегрузить init, чтобы выбрать начальные значения. Например : call one_array%init(size,4) и call two_arrays%init(size, 5,8).

Итак, необходима перегрузка init. Что-то вроде этого (для One_Array_t):

  interface init
     module procedure one_array_init, one_array_init2
  end interface init

Но это не соответствует abstract_init и я не смог бы выполнить эту перегрузку.

Это возможно или нет? Спасибо за ответы.

Посмотрите на общий

Ian Bush 14.06.2024 13:11

@ Ян Буш. Спасибо за эту идею. Я не думал об этом. Я постараюсь. У вас был пример?

Stef1611 14.06.2024 13:16

@ Ян Буш. Я попробовал и получил следующее сообщение об ошибке: Undefined specific binding 'one_array_init2' as target of GENERIC 'init'

Stef1611 14.06.2024 13:28

Разве вы не можете пойти совершенно скучным путем one_array%init(size,[4]) и two_arrays%init(size,[5,8])?

francescalus 14.06.2024 14:38

@francescalus. В данном конкретном случае я могу сделать это с массивом нулевого размера. Но если быть более общим, можно ли перегрузить процедуру, объявленную в абстрактном типе?

Stef1611 14.06.2024 14:41

Определенная процедура, привязанная к типу, переопределяется, а не перегружается, и универсальная процедура, привязанная к типу, не может иметь то же имя, что и конкретная процедура, привязанная к типу этого типа.

francescalus 14.06.2024 15:02

@Франческаку. Так возможно или нет сделать то, что я просил?

Stef1611 14.06.2024 15:06

Перегрузить init невозможно, потому что init — это конкретная процедура, а не универсальная процедура.

francescalus 14.06.2024 16:18

@francescalus. Спасибо за ответ. Итак, есть ли другое решение для перегрузки процедуры init?

Stef1611 14.06.2024 20:20

Действительно ли необходимо сделать процедуру init «виртуальной» (= процедурой с привязкой к типу родительского/абстрактного типа)? stackoverflow.com/a/733393/3501546

roygvib 15.06.2024 09:51

@roygvib. В этом примере используется конструктор, но это может быть другая подпрограмма, не обязательно init

Stef1611 15.06.2024 10:18

Как насчет определения процедур с привязкой к типу init1 и init2 с разными сигнатурами и присвоения им общего имени init в родительском/базовом типе, а затем переопределения одного из init1 и init2 в дочерних типах...?

roygvib 15.06.2024 11:27
Сила классов Java: сравнение с языком C
Сила классов Java: сравнение с языком C
Абстракция" - это процесс упрощения сложных сущностей или концепций реального мира с целью их применения в форме программирования. В Java класс...
1
12
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

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

module test_m
    implicit none

    type, abstract :: Parent_t
    contains
        generic   :: sub => sub1, sub2
        procedure :: sub1 => Parent_sub1
        procedure :: sub2 => Parent_sub2
    endtype

    type, extends(Parent_t) :: Child1_t
    contains
        procedure :: sub1 => Child1_sub1
    endtype

    type, extends(Parent_t) :: Child2_t
    contains
        procedure :: sub2 => Child2_sub2
    endtype

contains

    subroutine Parent_sub1(this, n)
        class(Parent_t) :: this
        integer :: n
        stop "sub1 not implemented"
    end
    subroutine Parent_sub2(this, n1, n2)
        class(Parent_t) :: this
        integer :: n1, n2
        stop "sub2 not implemented"
    end

    subroutine Child1_sub1(this, n)
        class(Child1_t) :: this
        integer :: n
        print *, "Child1: n = ", n
    end
    subroutine Child2_sub2(this, n1, n2)
        class(Child2_t) :: this
        integer :: n1, n2
        print *, "Child2: n1, n2 = ", n1, n2
    end
end module

program main
    use test_m
    implicit none
    type(Child1_t) :: c1
    type(Child2_t) :: c2

    call c1 % sub( 100 )
    call c2 % sub( 1, 2 )

    !! call c1 % sub( 1, 2 )  !! stop
    !! call c2 % sub( 100 )   !! stop
end

(можно протестировать на на этой странице)

Здесь я не использовал абстрактный интерфейс для родительского типа, так что в дочернем типе может быть реализована только одна интересующая процедура (например, sub1). (При необходимости в дочернем типе можно определить как sub1, так и sub2.) Новую подпрограмму, такую ​​как sub3(), также можно добавить позже в родительский тип.

Другой подход может заключаться в том, чтобы не использовать перегрузку, а (как также упоминалось в комментариях) просто определить одну подпрограмму, которая получает более «общий» аргумент (например, массивы, производные типы и т. д.).

(Кстати, если init() используется как «конструктор» (или «инициализатор»), я обычно не делаю его «виртуальным» в родительском типе, а напрямую определяю его в каждом дочернем типе, если конкретный тип известен инициализация и подпись init() могут различаться у разных дочерних типов. Для сравнения, этот Вопросы и ответы для C++ также может быть связан.)

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