2016-01-28 7 views
6

Próbuję zrozumieć różnicę między abstrakcyjnymi interfejsami a "normalnymi" interfejsami. Co sprawia, że ​​interfejs jest abstrakcyjny? Kiedy każdy jest potrzebny?Fortran - Różnice między interfejsami ogólnymi i specyficznymi

Załóżmy przykłady poniżej

module abstract_type_mod 
    implicit none 

    type, abstract :: abstract_t 
    contains 
    procedure(abstract_foo), pass, deferred :: Foo 
    end type 

    interface 
    subroutine abstract_foo (this, a, b) 
     import :: abstract_t 
     implicit none 
     class(abstract_t), intent(in) :: this 
     real,    intent(in) :: a 
     real,    intent(out) :: b 
    end subroutine 
    end interface 

end module 

module concrete_type_mod 
    use abstract_type_mod 
    implicit none 

    type, extends (abstract_t) :: concrete_t 
    contains 
    procedure, pass :: Foo 
    end type 

    contains 

    subroutine Foo (this, a, b) 
    implicit none 
    class(concrete_t), intent(in) :: this 
    real,    intent(in) :: a 
    real,    intent(out) :: b 

    b = 2 * a 

    end subroutine 
end module 

module ifaces_mod 
    implicit none 

    interface 
    subroutine foo_sub (a, b) 
     implicit none 
     real, intent(in) :: a 
     real, intent(out) :: b 
    end subroutine 
    end interface 

end module 

module subs_mod 
    implicit none 

    contains 

    pure subroutine module_foo (a, b) 
    implicit none 
    real, intent(in) :: a 
    real, intent(out) :: b 

    b = 2 * a 

    end subroutine 

end module 

program test 
    use ifaces_mod 
    use subs_mod 
    use concrete_type_mod 
    implicit none 

    type(concrete_t) :: concrete 
    procedure(foo_sub) :: external_sub 
    procedure(foo_sub), pointer :: foo_ptr 
    real :: b 

    foo_ptr => external_sub 

    call foo_ptr (0.0, b) 
    print*, b 

    foo_ptr => module_foo 

    call foo_ptr (1.0, b) 
    print*, b 

    call concrete%Foo (1.0, b) 
    print*, b 

end program 

pure subroutine external_sub (a, b) 
    implicit none 
    real, intent(in) :: a 
    real, intent(out) :: b 

    b = a + 5 

end subroutine 

Wyjście jest

5.000000 
2.000000 
2.000000 

Nie używałem abstrakcyjnych interfejsów tutaj. Przynajmniej myślę, że nie miałem? Robiłem to przez jakiś czas i nigdy nie użyłem abstrakcyjnego "kwalifikatora" na interfejsach. Wygląda na to, że nie znalazłem przypadku, w którym wymagane jest używanie abstrakcyjnych interfejsów.

Czy ktoś mógłby mnie oświecić?

PS: Kompilator Intel wizualna Fortran Composer XE 2013 z dodatkiem SP1 3.


Edit:

Cytowanie Metcalf, Reid i Cohen w Modern Fortran Poradnik:

W Fortran 95, aby zgłosić fikcyjną lub zewnętrzną procedurę z jawnym interfejsem , należy użyć bloku interfejsu. To jest w porządku dla pojedynczej procedury, ale jest nieco gęste dla deklarowania kilku procedur , które mają ten sam interfejs (oprócz nazw procedur ). Ponadto, w Fortran 2003, istnieje kilka sytuacji, w których jest to niemożliwe , gdy jest to niemożliwe (elementy wskaźnika procedury lub procedury związane z typem abstrakcyjnym ).

Czy mój kompilator błędnie akceptuje poniższy kod, a także powyższy typ abstrakcyjny?

module ifaces_mod 
    implicit none 

    interface 
    subroutine foo_sub (a, b) 
     implicit none 
     real, intent(in) :: a 
     real, intent(out) :: b 
    end subroutine 
    end interface 

end module 

module my_type_mod 
    use ifaces_mod 
    implicit none 

    type my_type_t 
    procedure(foo_sub), nopass, pointer :: Foo => null() 
    end type 

end module 

W obu przypadkach powiedziałbym, że faktycznie zadeklarowałem abstrakcyjne interfejsy bez użycia abstrakcyjnego słowa kluczowego. Myślę, że moje zamieszanie ma korzenie w tym, że kompilator akceptuje kod taki jak ten.

Odpowiedz

4

„normalna” interfejsy - znany przez normę jako określonych blokach interfejsu (jak użyć w tytule pytanie) - są po prostu normalne bloki interfejsowe do jakiegoś postępowania. Dlatego:

interface 
    subroutine foo_sub 
    end subroutine 
end interface 

oznacza, że ​​istnieje rzeczywisty (zewnętrzne) podprogram foo_sub i jest on zgodny z określonego interfejsu.

abstrakcyjny interfejs

abstract interface 
    subroutine foo_sub_abs 
    end subroutine 
end interface 

tylko określa, jak niektórzy procedura może wyglądać, ale nazwa jest nazwą interfejsu, a nie jakiejkolwiek rzeczywistej procedury.Może być stosowany dla Procedura A wskaźników

procedure(foo_sub_abs), pointer :: p 

lub obojętne argumentów

subroutine bar(f) 
    procedure(foo_sub_abs) :: f 

a to oznacza, że ​​rzeczywista procedura, do której p wskaże lub która jest przekazywana jako f zgodny z abstrakcyjnego interfejsu .

Należy pamiętać, że w obu dawnych przykładach można użyć istniejącej procedury zamiast abstrakcyjnego interfejsu. Musi on mieć jawny interfejs dostępny w zakresie (zazwyczaj jest w tym samym module lub w module, który jest używany).


O ile wiem (ale patrz @ komentarzu IanH za poniżej) kompilator może odmówić kod:

interface 
    subroutine abstract_foo (this, a, b) 
     import :: abstract_t 
     implicit none 
     class(abstract_t), intent(in) :: this 
     real,    intent(in) :: a 
     real,    intent(out) :: b 
    end subroutine 
    end interface 

ponieważ nie istnieje żadna faktyczna procedura nazwie abstract_foo. Niektóre kompilatory nie diagnozują tego, ale mogą.


Dość niezwiązane są ogólne interfejsy. Można je rozpoznać, ponieważ nie jest to nazwa procedury generycznej po słowie interface

interface generic_sub 
    procedure sub1 

    subroutine sub2(...) 
    end subroutine 
    end interface 

Tutaj sub1 i sub2 zarówno istnieją, sub1 jest już znany i ma już wyraźny interfejs dostępny, sub2 jest zewnętrzny i wygląda jak Interfejs określa, a obie są specyficzne procedury ogólne generic_sub. To całkiem inne użycie.

Następnie zadzwonić

call generic_sub(...) 

i zgodnie z przekazanych argumentów, kompilator wybiera, który nazywany jest specjalna procedura, jeśli jest sub1 lub sub2.

+0

Dziękuję, Władimir. Przykład, który przysporzył mi więcej kłopotów, jest naprawdę tym, który zawiera typy abstrakcyjne. Koncepcyjnie, powiedziałbym, że interfejsy, które deklaruję, są abstrakcyjne, ale nigdy nie musiałem ich deklarować jako takich. To doprowadziło mnie do wniosku, że naprawdę nie wiedziałem, co to jest. Teraz o wskaźnikach procedur i argumentach atrapa procedury. Nie deklaruję też dla nich abstrakcyjnych interfejsów. Czy możesz podać przykład, który po prostu nie zadziała, jeśli nie ogłoszę abstrakcyjnego interfejsu? (Z wyjątkiem tego, o którym już powiedziałeś, że kompilator może odrzucić powyższe.) – booNlatoT

+0

Nigdy nie potrzebujesz ściśle abstrakcyjnych interfejsów. Zawsze możesz stworzyć fikcyjną procedurę i wskazać ją w procedurze() '. Dlatego abstrakcyjny interfejs jest głównie dla wygody użytkownika i dla kompletności języka. –

+0

Edytowałem mój oryginalny wpis. Czy możesz rzucić na to okiem i powiedzieć, czy mój wniosek jest właściwy, czy nie? Ponadto, kiedy mówisz "utwórz procedurę pozorowaną", czy chcesz zgłosić jakąś procedurę pośredniczącą, której jawny interfejs będzie używany? Dziękuję ponownie. – booNlatoT