我正在开发一个面向对象的 Fortran 代码,用于具有抽象类型支持的多态性的数值优化。因为这是一个很好的 TDD 实践,所以我尝试在抽象类型中编写所有优化测试class(generic_optimizer)
,然后应该由每个实例化的类运行,例如,由type(newton_raphson)
.
所有优化测试都具有对 的调用call my_problem%solve(...)
,它被定义为deferred
抽象类型,当然每个派生类型都有不同的实现。
问题是:如果在每个非抽象类中我将延迟函数定义为non_overridable
,则会出现分段错误,例如:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) where
#0 0x0000000000000000 in ?? ()
#1 0x0000000000913efe in __newton_raphson_MOD_nr_solve ()
#2 0x00000000008cfafa in MAIN__ ()
#3 0x00000000008cfb2b in main ()
#4 0x0000003a3c81ed5d in __libc_start_main () from /lib64/libc.so.6
#5 0x00000000004048f9 in _start ()
经过反复试验,我注意到如果删除non_overridable
声明,我可以避免错误。在这种情况下,这不是问题,但我想强制执行这一点,因为此代码不太可能存在两级多态性。相反,我是否违反了标准中的任何要求?
这是重现错误的示例代码。我一直在用 gfortran 5.3.0 和 6.1.0 对其进行测试。
module generic_type_module
implicit none
private
type, abstract, public :: generic_type
real(8) :: some_data
contains
procedure (sqrt_interface), deferred :: square_root
procedure, non_overridable :: sqrt_test
end type generic_type
abstract interface
real(8) function sqrt_interface(this,x) result(sqrtx)
import generic_type
class(generic_type), intent(in) :: this
real(8), intent(in) :: x
end function sqrt_interface
end interface
contains
subroutine sqrt_test(this,x)
class(generic_type), intent(in) :: this
real(8), intent(in) :: x
print *, 'sqrt(',x,') = ',this%square_root(x)
end subroutine sqrt_test
end module generic_type_module
module actual_types_module
use generic_type_module
implicit none
private
type, public, extends(generic_type) :: crashing
real(8) :: other_data
contains
procedure, non_overridable :: square_root => crashing_square_root
end type crashing
type, public, extends(generic_type) :: working
real(8) :: other_data
contains
procedure :: square_root => working_square_root
end type working
contains
real(8) function crashing_square_root(this,x) result(sqrtx)
class(crashing), intent(in) :: this
real(8), intent(in) :: x
sqrtx = sqrt(x)
end function crashing_square_root
real(8) function working_square_root(this,x) result(sqrtx)
class(working), intent(in) :: this
real(8), intent(in) :: x
sqrtx = sqrt(x)
end function working_square_root
end module actual_types_module
program deferred_test
use actual_types_module
implicit none
type(crashing) :: crashes
type(working) :: works
call works%sqrt_test(2.0_8)
call crashes%sqrt_test(2.0_8)
end program