我正在学习 Fortran 的面向对象编程。我好奇,当编译时参数的类型未知时,重载类型绑定过程有什么意义。
让我一步一步解释我的问题(这些程序只是为了提高我的 Fortran 技能的例子)
第一个程序:类型绑定过程的重载
module my_mod
implicit none
type :: my_type_t
character(len=128) :: my_text
contains
procedure :: integer_print, real_print
generic :: my_print => integer_print, real_print
end type my_type_t
contains
subroutine integer_print(this, my_int)
class(my_type_t), intent(in) :: this
integer, intent(in) :: my_int
write (*,"(a,a,i0)") trim(this%my_text),' integer ', my_int
end subroutine integer_print
subroutine real_print(this, my_real)
class(my_type_t), intent(in) :: this
real, intent(in) :: my_real
write (*,"(a,a,f0.3)") trim(this%my_text),' real ', my_real
end subroutine real_print
end module my_mod
program my_pgm
use my_mod
implicit none
type(my_type_t) :: my_var
my_var%my_text = "Hello"
call my_var%my_print(10)
call my_var%my_print(9.9)
end program my_pgm
它给出了预期的结果。使用integer_print
或real_print
,取决于参数的类型my_print
(整数或实数)。
第二个程序(或者应该写成步骤):使用了一个抽象类型,并且有两个派生类型:my_int_t
和my_real_t
。它与第一个例子非常相似。但是,使用了两种类型:一个用于整数,另一个用于实数。
module my_mod
implicit none
type, abstract :: my_abstract_t
end type my_abstract_t
type, extends(my_abstract_t) :: my_int_t
integer :: an_integer
end type my_int_t
type, extends(my_abstract_t) :: my_real_t
real :: a_real
end type my_real_t
type :: my_type_t
character(len=128) :: my_text
contains
procedure :: integer_print, real_print
generic :: my_print => integer_print, real_print
end type my_type_t
contains
subroutine integer_print(this, my_int)
class(my_type_t), intent(in) :: this
type(my_int_t), intent(in) :: my_int
write (*,"(a,a,i0)") trim(this%my_text),' integer ', my_int%an_integer
end subroutine integer_print
subroutine real_print(this, my_real)
class(my_type_t), intent(in) :: this
type(my_real_t), intent(in) :: my_real
write (*,"(a,a,f0.3)") trim(this%my_text),' real ', my_real%a_real
end subroutine real_print
end module my_mod
program my_pgm
use my_mod
implicit none
type(my_type_t) :: my_var
type(my_int_t) :: my_int
type(my_real_t) :: my_real
my_var%my_text = "Hello"
my_int%an_integer = 10
my_real%a_real = 9.9
call my_var%my_print(my_int)
call my_var%my_print(my_real)
end program my_pgm
my_int
和的类型my_real
在编译类型时是已知的,因此输出是正确的。并且my_var%my_print(...)
无论变量类型是什么(my_int_t
或my_real_t
),都会使用相同的调用,就像第一个示例中那样。
但是,现在这是我的问题。
program my_pgm
use my_mod
implicit none
type(my_type_t) :: my_var
class(my_abstract_t), allocatable :: my_number
allocate(my_int_t::my_number)
! or allocate(my_real_t::my_number)
my_var%my_text = "Hello"
select type (my_number)
type is (my_int_t)
my_number%an_integer = 10
type is (my_real_t)
my_number%a_real = 9.9
end select
select type (my_number)
type is (my_int_t)
call my_var%my_print(my_number)
type is (my_real_t)
call my_var%my_print(my_number)
end select
end program my_pgm
的类型my_number
在编译时是未知的。因此,我必须使用一段我认为非常多余的代码:
select type (my_number)
type is (my_int_t)
call my_var%my_print(my_number)
type is (my_real_t)
call my_var%my_print(my_number)
end select
我本来希望只写一行 : ,call my_var%my_print(...)
就像第一和第二个例子一样。我是不是应该得出结论,在第三个例子中,过程重载并不重要,最好直接在块中使用integer_print
and ?还是有什么我没理解的地方?real_print
select type
编辑1
按照 Francescalus 的注释,如果我理解正确的话,我的确无法避免select type
阻塞。因此,我按照以下方式修改了程序。
module my_mod
implicit none
type, abstract :: my_abstract_t
end type my_abstract_t
type, extends(my_abstract_t) :: my_int_t
integer :: an_integer
end type my_int_t
type, extends(my_abstract_t) :: my_real_t
real :: a_real
end type my_real_t
type :: my_type_t
character(len=128) :: my_text
contains
procedure, private :: real_print, integer_print
procedure, public :: my_print
end type my_type_t
contains
subroutine integer_print(this, my_int)
class(my_type_t), intent(in) :: this
type(my_int_t), intent(in) :: my_int
write (*,"(a,a,i0)") trim(this%my_text),' integer ', my_int%an_integer
end subroutine integer_print
subroutine real_print(this, my_real)
class(my_type_t), intent(in) :: this
type(my_real_t), intent(in) :: my_real
write (*,"(a,a,f0.3)") trim(this%my_text),' real ', my_real%a_real
end subroutine real_print
subroutine my_print(this,my_number)
class(my_type_t), intent(in) :: this
class(my_abstract_t), intent(in) :: my_number
select type (my_number)
type is (my_int_t)
call this%integer_print(my_number)
type is (my_real_t)
call this%real_print(my_number)
end select
end subroutine my_print
end module my_mod
program my_pgm
use my_mod
implicit none
type(my_type_t) :: my_var
class(my_abstract_t), allocatable :: my_number1, my_number2
my_number1 = my_int_t(an_integer = 10)
my_number2 = my_real_t(a_real = 9.9)
my_var%my_text = "Hello"
call my_var%my_print(my_number1)
call my_var%my_print(my_number2)
end program my_pgm
任何评论都将受到欢迎。
可以使用双重分派,也称为访问者模式。
这是代码的示例实现。它有一个明显的限制,即必须已知类型。但是,避免
my_type_t
使用,并且可以自由添加其他扩展类型。select_type
my_abstract_type
主要的一点是,在
type(my_type_t)
已经可用的情况下进行另一次调度,并将打印的实现转移到具有数字数据的各个类型,而my_abstract_t
这些数据必须知道其结构my_type_t
- 这是一个缺点。