2016-01-28 15 views
6

Tôi đang cố gắng hiểu sự khác biệt giữa giao diện trừu tượng và giao diện "bình thường". Điều gì làm cho một giao diện trừu tượng? Mỗi khi cần thiết khi nào?Fortran - Sự khác biệt giữa giao diện chung và giao diện cụ thể

Giả sử ví dụ dưới đây

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 

Đầu ra là

5.000000 
2.000000 
2.000000 

tôi đã không sử dụng giao diện trừu tượng ở đây. Ít nhất tôi nghĩ tôi havent? Tôi đã làm điều này một thời gian và tôi chưa bao giờ sử dụng "vòng loại" trừu tượng trên các giao diện. Dường như tôi chưa tìm thấy trường hợp sử dụng giao diện trừu tượng.

Ai đó có thể khai sáng cho tôi ở đây?

PS: Compiler Intel Visual Fortran Composer XE 2013 SP1 Update 3.


Edit:

Trích dẫn Metcalf, Reid và Cohen trong Modern Fortran Giải thích:

Trong Fortran 95, để khai báo một thủ tục giả hoặc bên ngoài với giao diện rõ ràng , người dùng cần sử dụng khối giao diện. Đây là tiền phạt cho một quy trình duy nhất, nhưng có phần tiết lộ để khai báo một số thủ tục có cùng giao diện (ngoài thủ tục tên). Hơn nữa, trong Fortran 2003, có một số trường hợp nơi điều này trở thành không thể (thành phần con trỏ thủ tục hoặc thủ tục ràng buộc kiểu trừu tượng).

Vì vậy, trình biên dịch của tôi có lỗi khi chấp nhận mã bên dưới và cũng là trình biên dịch có loại trừu tượng ở trên không?

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 

Trong cả hai trường hợp, tôi thực sự đã tuyên bố giao diện trừu tượng mà không sử dụng từ khóa trừu tượng. Tôi nghĩ rằng sự nhầm lẫn của tôi có nguồn gốc trên thực tế là trình biên dịch được chấp nhận mã như thế này.

Trả lời

4

Giao diện "bình thường" - được biết theo tiêu chuẩn là khối giao diện cụ thể (như bạn sử dụng trong tiêu đề câu hỏi) - chỉ là các khối giao diện bình thường đối với một số quy trình. Do đó:

interface 
    subroutine foo_sub 
    end subroutine 
end interface 

có nghĩa là có một thực thể con (bên ngoài) tên là foo_sub và nó tuân theo giao diện được chỉ định.

Một giao diện trừu tượng

abstract interface 
    subroutine foo_sub_abs 
    end subroutine 
end interface 

chỉ định cách một số thủ tục có thể trông như thế nào, nhưng tên là tên của giao diện, chứ không phải bất kỳ thủ tục thực tế.Nó có thể được sử dụng cho một thủ tục con trỏ

procedure(foo_sub_abs), pointer :: p 

hoặc cho một đối số giả

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

và nó có nghĩa rằng các thủ tục thực tế mà p sẽ chỉ hoặc định được thông qua như f phù hợp với giao diện trừu tượng .

Lưu ý rằng bạn được phép sử dụng một số quy trình hiện có thay vì giao diện trừu tượng trong cả hai ví dụ trước đây. Nó chỉ cần có giao diện rõ ràng có sẵn trong phạm vi (thường là trong cùng một mô-đun, hoặc trong một mô-đun được sử dụng).


Theo như tôi biết (nhưng xem @ bình luận IanH của dưới đây) trình biên dịch được phép từ chối mã của bạn:

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 

vì có tồn tại không có thủ tục thực tế tên abstract_foo. Một số trình biên dịch không chẩn đoán điều này, nhưng chúng có thể.


Khá không liên quan là các giao diện chung. Bạn có thể nhận ra chúng, bởi vì có một tên của một thủ tục chung sau chữ interface

interface generic_sub 
    procedure sub1 

    subroutine sub2(...) 
    end subroutine 
    end interface 

Đây sub1sub2 cả tồn tại, sub1 đã được biết đến và có giao diện đã rõ ràng có sẵn, sub2 là bên ngoài và trông như giao diện chỉ định, và cả hai đều là thủ tục cụ thể của chung generic_sub. Đây là cách sử dụng khá khác.

Bạn sau đó gọi

call generic_sub(...) 

và theo các đối số bạn vượt qua, trình biên dịch chọn mà thủ tục cụ thể được gọi là, nếu nó là sub1, hoặc sub2.

+0

Cảm ơn bạn, Vladmir. Ví dụ đã mang lại cho tôi nhiều rắc rối hơn thực sự là một trong những loại trừu tượng. Về mặt khái niệm, tôi muốn nói các giao diện mà tôi khai báo có trừu tượng, nhưng tôi chưa bao giờ phải khai báo chúng như vậy. Điều này dẫn tôi đến kết luận rằng tôi thực sự không biết chúng là gì. Bây giờ, về các con trỏ thủ tục và các đối số giả lập thủ tục. Tôi cũng không khai báo giao diện trừu tượng cho những người đó. Bạn có thể cho tôi một ví dụ mà chỉ đơn giản là sẽ không hoạt động nếu tôi không khai báo một giao diện trừu tượng? (Ngoại trừ một trong những bạn đã nói trình biên dịch có thể từ chối ở trên.) – booNlatoT

+0

Bạn không bao giờ cần giao diện trừu tượng. Bạn luôn có thể tạo một thủ tục giả và trỏ đến nó trong 'procedure()'. Do đó, giao diện trừu tượng chủ yếu là để thuận tiện cho bạn và cho sự hoàn chỉnh của ngôn ngữ. –

+0

Tôi đã chỉnh sửa bài đăng gốc của mình. Bạn có thể xem nó và cho tôi biết liệu kết luận của tôi có đúng không? Ngoài ra, khi bạn nói "tạo ra một thủ tục giả", bạn có nghĩa là để khai báo một số loại thủ tục sơ khai có giao diện rõ ràng sẽ được sử dụng? Cảm ơn bạn một lần nữa. – booNlatoT

Các vấn đề liên quan