Ich entwickle einen objektorientierten Fortran-Code für die numerische Optimierung mit Polymorphismus, der von abstrakten Typen unterstützt wird. Da es eine gute TDD-Praxis ist, versuche ich, alle Optimierungstests in dem abstrakten Typ class(generic_optimizer)
zu schreiben, der dann von jeder instanziierten Klasse ausgeführt werden sollte, z. B. von type(newton_raphson)
.Segmentierungsfehler mit zurückgestellten Funktionen und non_overridable Schlüsselwort
Alle Optimierungstests verfügen über einen Aufruf an call my_problem%solve(...)
, der im abstrakten Typ als deferred
definiert ist und natürlich eine andere Implementierung in jedem abgeleiteten Typ aufweist.
Die Frage ist: wenn in jeder nicht-abstrakten Klasse I die latente Funktion als non_overridable
definieren, ich Segmentierungsfehler erhalten wie:
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()
Nach einigem trial-and-error, ich habe bemerkt, dass Ich kann den Fehler vermeiden, wenn ich die non_overridable
Deklaration entferne. In diesem Fall ist das kein Problem, aber ich wollte dies erzwingen, da für diesen Code zwei Polymorphismeniveaus unwahrscheinlich sind. Habe ich stattdessen irgendwelche Anforderungen aus dem Standard verletzt?
Hier ist ein Beispielcode, der den Fehler reproduziert. Ich habe es mit gfortran 5.3.0 und 6.1.0 getestet.
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
Aus einem kurzen Blick, gibt es keinen offensichtlichen Grund, warum das 'non_overridable' Attribut verboten ist (und später nicht zu überschreiben). Ich habe jedoch keinen Zugriff auf einen Compiler, um das Problem zu reproduzieren. – francescalus
Sieht für mich wie ein Compiler-Fehler aus. – IanH
Was hat das mit Deferreds zu tun? –