2012-04-05 1 views
2

Я беру пример из «Fortran 95/2003, объясненный» Меткалфом и др., Так как собственный код нацелен на то же самое.Как перегрузить оператор для производного типа, который расширяет абстрактный тип?

type, abstract :: my_numeric_type 
contains 
    private 
    procedure(op2), deferred :: add 
    generic, public :: operator(+) => add 
end 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 

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

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

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 

    allocate(my_integer :: r) 
    select type (b) 
     type is (my_integer) 
      r = a+b 
    end select 
end function 
+0

какой компилятор вы попробовали? –

+0

Последняя версия ifort. – tiam

ответ

3

Это работает для меня, но это выглядит довольно сложным (слишком много select type). Я сделал ценность общедоступной для простого вывода, в противном случае вам нужен пользовательский getter и setter.

module num 

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

    abstract interface 
     subroutine op(a,b) 
      import :: my_numeric_type 
      class(my_numeric_type), intent(out) :: a 
      class(my_numeric_type), intent(in) :: b 
     end subroutine op 
     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 

    type, extends(my_numeric_type) :: my_integer 
     integer, public :: value 
    contains 
     procedure :: add => add_my_integer 
     procedure :: ass => ass_my_integer 
    end type 

    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 

     select type (b) 
      type is (my_integer) 
       allocate(my_integer :: r) 
       select type (r) 
        type is (my_integer) 
        r%value = a%value+b%value 
       end select 
     end select 
    end function 


    subroutine ass_my_integer(a,b) 
     class(my_integer), intent(out) :: a 
     class(my_numeric_type), intent(in) :: b 

     select type (b) 
      type is (my_integer) 
        a%value = b%value 
     end select 
    end subroutine 

end module 

program main 
    use num 

    class(my_integer), allocatable :: a, b, c 
    allocate(my_integer :: a) 
    allocate(my_integer :: b) 
    allocate(my_integer :: c) 
    a=my_integer(1) 
    b=my_integer(2) 
    c = a+b 
    write (*,*) c%value 
end program 
+0

Кажется настолько неэффективным, что к каждой операции прилагается оператор «если»! – tiam

+0

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

+0

@tiam: он, вероятно, не будет слишком неэффективным, если ваш код проводит большую часть своего времени, выполняя большие операции массива, что, безусловно, делает мой код Fortran. – bdforbes